summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /compiler/rustc_trait_selection
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml27
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs240
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs177
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs40
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs903
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs163
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs80
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs747
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs308
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs112
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2765
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs272
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs3119
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs757
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs88
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs863
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs866
-rw-r--r--compiler/rustc_trait_selection/src/traits/on_unimplemented.rs425
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2150
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs73
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs118
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/mod.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs354
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs117
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs42
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs168
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs68
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs55
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs43
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/relationships.rs58
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs1009
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs1266
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2698
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs531
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs395
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs273
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs368
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs888
42 files changed, 22709 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
new file mode 100644
index 000000000..566f236f2
--- /dev/null
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+name = "rustc_trait_selection"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+doctest = false
+
+[dependencies]
+rustc_parse_format = { path = "../rustc_parse_format" }
+tracing = "0.1"
+rustc_attr = { path = "../rustc_attr" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_index = { path = "../rustc_index" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_query_system = { path = "../rustc_query_system" }
+rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
new file mode 100644
index 000000000..8b7e8984a
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -0,0 +1,240 @@
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{self, TraitEngine};
+use rustc_errors::struct_span_err;
+use rustc_hir as hir;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{ToPredicate, TypeVisitable};
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::Span;
+
+#[derive(Copy, Clone, Debug)]
+pub enum AutoderefKind {
+ Builtin,
+ Overloaded,
+}
+
+struct AutoderefSnapshot<'tcx> {
+ at_start: bool,
+ reached_recursion_limit: bool,
+ steps: Vec<(Ty<'tcx>, AutoderefKind)>,
+ cur_ty: Ty<'tcx>,
+ obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+pub struct Autoderef<'a, 'tcx> {
+ // Meta infos:
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ span: Span,
+ overloaded_span: Span,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+
+ // Current state:
+ state: AutoderefSnapshot<'tcx>,
+
+ // Configurations:
+ include_raw_pointers: bool,
+ silence_errors: bool,
+}
+
+impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
+ type Item = (Ty<'tcx>, usize);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let tcx = self.infcx.tcx;
+
+ debug!("autoderef: steps={:?}, cur_ty={:?}", self.state.steps, self.state.cur_ty);
+ if self.state.at_start {
+ self.state.at_start = false;
+ debug!("autoderef stage #0 is {:?}", self.state.cur_ty);
+ return Some((self.state.cur_ty, 0));
+ }
+
+ // If we have reached the recursion limit, error gracefully.
+ if !tcx.recursion_limit().value_within_limit(self.state.steps.len()) {
+ if !self.silence_errors {
+ report_autoderef_recursion_limit_error(tcx, self.span, self.state.cur_ty);
+ }
+ self.state.reached_recursion_limit = true;
+ return None;
+ }
+
+ if self.state.cur_ty.is_ty_var() {
+ return None;
+ }
+
+ // Otherwise, deref if type is derefable:
+ let (kind, new_ty) =
+ if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
+ (AutoderefKind::Builtin, mt.ty)
+ } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+ (AutoderefKind::Overloaded, ty)
+ } else {
+ return None;
+ };
+
+ if new_ty.references_error() {
+ return None;
+ }
+
+ self.state.steps.push((self.state.cur_ty, kind));
+ debug!(
+ "autoderef stage #{:?} is {:?} from {:?}",
+ self.step_count(),
+ new_ty,
+ (self.state.cur_ty, kind)
+ );
+ self.state.cur_ty = new_ty;
+
+ Some((self.state.cur_ty, self.step_count()))
+ }
+}
+
+impl<'a, 'tcx> Autoderef<'a, 'tcx> {
+ pub fn new(
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ overloaded_span: Span,
+ ) -> Autoderef<'a, 'tcx> {
+ Autoderef {
+ infcx,
+ span,
+ overloaded_span,
+ body_id,
+ param_env,
+ state: AutoderefSnapshot {
+ steps: vec![],
+ cur_ty: infcx.resolve_vars_if_possible(base_ty),
+ obligations: vec![],
+ at_start: true,
+ reached_recursion_limit: false,
+ },
+ include_raw_pointers: false,
+ silence_errors: false,
+ }
+ }
+
+ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+ debug!("overloaded_deref_ty({:?})", ty);
+
+ let tcx = self.infcx.tcx;
+
+ // <ty as Deref>
+ let trait_ref = TraitRef {
+ def_id: tcx.lang_items().deref_trait()?,
+ substs: tcx.mk_substs_trait(ty, &[]),
+ };
+
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+
+ let obligation = traits::Obligation::new(
+ cause.clone(),
+ self.param_env,
+ ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+ );
+ if !self.infcx.predicate_may_hold(&obligation) {
+ debug!("overloaded_deref_ty: cannot match obligation");
+ return None;
+ }
+
+ let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+ let normalized_ty = fulfillcx.normalize_projection_type(
+ &self.infcx,
+ self.param_env,
+ ty::ProjectionTy {
+ item_def_id: tcx.lang_items().deref_target()?,
+ substs: trait_ref.substs,
+ },
+ cause,
+ );
+ let errors = fulfillcx.select_where_possible(&self.infcx);
+ if !errors.is_empty() {
+ // This shouldn't happen, except for evaluate/fulfill mismatches,
+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+ // by design).
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
+ return None;
+ }
+ let obligations = fulfillcx.pending_obligations();
+ debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+ self.state.obligations.extend(obligations);
+
+ Some(self.infcx.resolve_vars_if_possible(normalized_ty))
+ }
+
+ /// Returns the final type we ended up with, which may be an inference
+ /// variable (we will resolve it first, if we want).
+ pub fn final_ty(&self, resolve: bool) -> Ty<'tcx> {
+ if resolve {
+ self.infcx.resolve_vars_if_possible(self.state.cur_ty)
+ } else {
+ self.state.cur_ty
+ }
+ }
+
+ pub fn step_count(&self) -> usize {
+ self.state.steps.len()
+ }
+
+ pub fn into_obligations(self) -> Vec<traits::PredicateObligation<'tcx>> {
+ self.state.obligations
+ }
+
+ pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
+ &self.state.steps
+ }
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn overloaded_span(&self) -> Span {
+ self.overloaded_span
+ }
+
+ pub fn reached_recursion_limit(&self) -> bool {
+ self.state.reached_recursion_limit
+ }
+
+ /// also dereference through raw pointer types
+ /// e.g., assuming ptr_to_Foo is the type `*const Foo`
+ /// fcx.autoderef(span, ptr_to_Foo) => [*const Foo]
+ /// fcx.autoderef(span, ptr_to_Foo).include_raw_ptrs() => [*const Foo, Foo]
+ pub fn include_raw_pointers(mut self) -> Self {
+ self.include_raw_pointers = true;
+ self
+ }
+
+ pub fn silence_errors(mut self) -> Self {
+ self.silence_errors = true;
+ self
+ }
+}
+
+pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+ // We've reached the recursion limit, error gracefully.
+ let suggested_limit = match tcx.recursion_limit() {
+ Limit(0) => Limit(2),
+ limit => limit * 2,
+ };
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0055,
+ "reached the recursion limit while auto-dereferencing `{:?}`",
+ ty
+ )
+ .span_label(span, "deref recursion limit reached")
+ .help(&format!(
+ "consider increasing the recursion limit by adding a \
+ `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
+ suggested_limit,
+ tcx.crate_name(LOCAL_CRATE),
+ ))
+ .emit();
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
new file mode 100644
index 000000000..9d30374f8
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -0,0 +1,177 @@
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::{self, TraitEngine, TraitEngineExt};
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::ObligationCause;
+use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
+use rustc_middle::traits::query::Fallible;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable};
+use rustc_span::{Span, DUMMY_SP};
+
+use std::fmt::Debug;
+
+pub use rustc_infer::infer::*;
+
+pub trait InferCtxtExt<'tcx> {
+ fn type_is_copy_modulo_regions(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ span: Span,
+ ) -> bool;
+
+ fn partially_normalize_associated_types_in<T>(
+ &self,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> InferOk<'tcx, T>
+ where
+ T: TypeFoldable<'tcx>;
+
+ /// Check whether a `ty` implements given trait(trait_def_id).
+ /// The inputs are:
+ ///
+ /// - the def-id of the trait
+ /// - the self type
+ /// - the *other* type parameters of the trait, excluding the self-type
+ /// - the parameter environment
+ ///
+ /// Invokes `evaluate_obligation`, so in the event that evaluating
+ /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown)
+ /// will be returned.
+ fn type_implements_trait(
+ &self,
+ trait_def_id: DefId,
+ ty: Ty<'tcx>,
+ params: SubstsRef<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> traits::EvaluationResult;
+}
+impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+ fn type_is_copy_modulo_regions(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ span: Span,
+ ) -> bool {
+ let ty = self.resolve_vars_if_possible(ty);
+
+ if !(param_env, ty).needs_infer() {
+ return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
+ }
+
+ let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
+
+ // This can get called from typeck (by euv), and `moves_by_default`
+ // rightly refuses to work with inference variables, but
+ // moves_by_default has a cache, which we want to use in other
+ // cases.
+ traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
+ }
+
+ /// Normalizes associated types in `value`, potentially returning
+ /// new obligations that must further be processed.
+ fn partially_normalize_associated_types_in<T>(
+ &self,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> InferOk<'tcx, T>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!("partially_normalize_associated_types_in(value={:?})", value);
+ let mut selcx = traits::SelectionContext::new(self);
+ let traits::Normalized { value, obligations } =
+ traits::normalize(&mut selcx, param_env, cause, value);
+ debug!(
+ "partially_normalize_associated_types_in: result={:?} predicates={:?}",
+ value, obligations
+ );
+ InferOk { value, obligations }
+ }
+
+ fn type_implements_trait(
+ &self,
+ trait_def_id: DefId,
+ ty: Ty<'tcx>,
+ params: SubstsRef<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> traits::EvaluationResult {
+ debug!(
+ "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
+ trait_def_id, ty, params, param_env
+ );
+
+ let trait_ref =
+ ty::TraitRef { def_id: trait_def_id, substs: self.tcx.mk_substs_trait(ty, params) };
+
+ let obligation = traits::Obligation {
+ cause: traits::ObligationCause::dummy(),
+ param_env,
+ recursion_depth: 0,
+ predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
+ };
+ self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
+ }
+}
+
+pub trait InferCtxtBuilderExt<'tcx> {
+ fn enter_canonical_trait_query<K, R>(
+ &mut self,
+ canonical_key: &Canonical<'tcx, K>,
+ operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
+ where
+ K: TypeFoldable<'tcx>,
+ R: Debug + TypeFoldable<'tcx>,
+ Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>;
+}
+
+impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
+ /// The "main method" for a canonicalized trait query. Given the
+ /// canonical key `canonical_key`, this method will create a new
+ /// inference context, instantiate the key, and run your operation
+ /// `op`. The operation should yield up a result (of type `R`) as
+ /// well as a set of trait obligations that must be fully
+ /// satisfied. These obligations will be processed and the
+ /// canonical result created.
+ ///
+ /// Returns `NoSolution` in the event of any error.
+ ///
+ /// (It might be mildly nicer to implement this on `TyCtxt`, and
+ /// not `InferCtxtBuilder`, but that is a bit tricky right now.
+ /// In part because we would need a `for<'tcx>` sort of
+ /// bound for the closure and in part because it is convenient to
+ /// have `'tcx` be free on this function so that we can talk about
+ /// `K: TypeFoldable<'tcx>`.)
+ fn enter_canonical_trait_query<K, R>(
+ &mut self,
+ canonical_key: &Canonical<'tcx, K>,
+ operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
+ where
+ K: TypeFoldable<'tcx>,
+ R: Debug + TypeFoldable<'tcx>,
+ Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
+ {
+ self.enter_with_canonical(
+ DUMMY_SP,
+ canonical_key,
+ |ref infcx, key, canonical_inference_vars| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ let value = operation(infcx, &mut *fulfill_cx, key)?;
+ infcx.make_canonicalized_query_response(
+ canonical_inference_vars,
+ value,
+ &mut *fulfill_cx,
+ )
+ },
+ )
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
new file mode 100644
index 000000000..282ee632c
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -0,0 +1,40 @@
+//! This crate defines the trait resolution method.
+//!
+//! - **Traits.** Trait resolution is implemented in the `traits` module.
+//!
+//! For more information about how rustc works, see the [rustc-dev-guide].
+//!
+//! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![allow(rustc::potential_query_instability)]
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(box_patterns)]
+#![feature(control_flow_enum)]
+#![feature(drain_filter)]
+#![feature(hash_drain_filter)]
+#![feature(label_break_value)]
+#![feature(let_chains)]
+#![feature(let_else)]
+#![feature(if_let_guard)]
+#![feature(never_type)]
+#![recursion_limit = "512"] // For rustdoc
+
+#[macro_use]
+extern crate rustc_macros;
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+#[macro_use]
+extern crate rustc_data_structures;
+#[macro_use]
+extern crate tracing;
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate smallvec;
+
+pub mod autoderef;
+pub mod infer;
+pub mod traits;
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
new file mode 100644
index 000000000..294c81d0b
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -0,0 +1,903 @@
+//! Support code for rustdoc and external tools.
+//! You really don't want to be using this unless you need to.
+
+use super::*;
+
+use crate::infer::region_constraints::{Constraint, RegionConstraintData};
+use crate::infer::InferCtxt;
+use crate::traits::project::ProjectAndUnifyResult;
+use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::{Region, RegionVid, Term};
+
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+
+use std::collections::hash_map::Entry;
+use std::collections::VecDeque;
+use std::iter;
+
+// FIXME(twk): this is obviously not nice to duplicate like that
+#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
+pub enum RegionTarget<'tcx> {
+ Region(Region<'tcx>),
+ RegionVid(RegionVid),
+}
+
+#[derive(Default, Debug, Clone)]
+pub struct RegionDeps<'tcx> {
+ larger: FxHashSet<RegionTarget<'tcx>>,
+ smaller: FxHashSet<RegionTarget<'tcx>>,
+}
+
+pub enum AutoTraitResult<A> {
+ ExplicitImpl,
+ PositiveImpl(A),
+ NegativeImpl,
+}
+
+#[allow(dead_code)]
+impl<A> AutoTraitResult<A> {
+ fn is_auto(&self) -> bool {
+ matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
+ }
+}
+
+pub struct AutoTraitInfo<'cx> {
+ pub full_user_env: ty::ParamEnv<'cx>,
+ pub region_data: RegionConstraintData<'cx>,
+ pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>,
+}
+
+pub struct AutoTraitFinder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> AutoTraitFinder<'tcx> {
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+ AutoTraitFinder { tcx }
+ }
+
+ /// Makes a best effort to determine whether and under which conditions an auto trait is
+ /// implemented for a type. For example, if you have
+ ///
+ /// ```
+ /// struct Foo<T> { data: Box<T> }
+ /// ```
+ ///
+ /// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type).
+ /// The analysis attempts to account for custom impls as well as other complex cases. This
+ /// result is intended for use by rustdoc and other such consumers.
+ ///
+ /// (Note that due to the coinductive nature of Send, the full and correct result is actually
+ /// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field
+ /// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send.
+ /// But this is often not the best way to present to the user.)
+ ///
+ /// Warning: The API should be considered highly unstable, and it may be refactored or removed
+ /// in the future.
+ pub fn find_auto_trait_generics<A>(
+ &self,
+ ty: Ty<'tcx>,
+ orig_env: ty::ParamEnv<'tcx>,
+ trait_did: DefId,
+ mut auto_trait_callback: impl FnMut(AutoTraitInfo<'tcx>) -> A,
+ ) -> AutoTraitResult<A> {
+ let tcx = self.tcx;
+
+ let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]) };
+
+ let trait_pred = ty::Binder::dummy(trait_ref);
+
+ let bail_out = tcx.infer_ctxt().enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ let result = selcx.select(&Obligation::new(
+ ObligationCause::dummy(),
+ orig_env,
+ trait_pred.to_poly_trait_predicate(),
+ ));
+
+ match result {
+ Ok(Some(ImplSource::UserDefined(_))) => {
+ debug!(
+ "find_auto_trait_generics({:?}): \
+ manual impl found, bailing out",
+ trait_ref
+ );
+ return true;
+ }
+ _ => {}
+ }
+
+ let result = selcx.select(&Obligation::new(
+ ObligationCause::dummy(),
+ orig_env,
+ trait_pred.to_poly_trait_predicate_negative_polarity(),
+ ));
+
+ match result {
+ Ok(Some(ImplSource::UserDefined(_))) => {
+ debug!(
+ "find_auto_trait_generics({:?}): \
+ manual impl found, bailing out",
+ trait_ref
+ );
+ true
+ }
+ _ => false,
+ }
+ });
+
+ // If an explicit impl exists, it always takes priority over an auto impl
+ if bail_out {
+ return AutoTraitResult::ExplicitImpl;
+ }
+
+ tcx.infer_ctxt().enter(|infcx| {
+ let mut fresh_preds = FxHashSet::default();
+
+ // Due to the way projections are handled by SelectionContext, we need to run
+ // evaluate_predicates twice: once on the original param env, and once on the result of
+ // the first evaluate_predicates call.
+ //
+ // The problem is this: most of rustc, including SelectionContext and traits::project,
+ // are designed to work with a concrete usage of a type (e.g., Vec<u8>
+ // fn<T>() { Vec<T> }. This information will generally never change - given
+ // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'.
+ // If we're unable to prove that 'T' implements a particular trait, we're done -
+ // there's nothing left to do but error out.
+ //
+ // However, synthesizing an auto trait impl works differently. Here, we start out with
+ // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing
+ // with - and progressively discover the conditions we need to fulfill for it to
+ // implement a certain auto trait. This ends up breaking two assumptions made by trait
+ // selection and projection:
+ //
+ // * We can always cache the result of a particular trait selection for the lifetime of
+ // an InfCtxt
+ // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T:
+ // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K'
+ //
+ // We fix the first assumption by manually clearing out all of the InferCtxt's caches
+ // in between calls to SelectionContext.select. This allows us to keep all of the
+ // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift
+ // them between calls.
+ //
+ // We fix the second assumption by reprocessing the result of our first call to
+ // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first
+ // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass,
+ // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing
+ // SelectionContext to return it back to us.
+
+ let Some((new_env, user_env)) = self.evaluate_predicates(
+ &infcx,
+ trait_did,
+ ty,
+ orig_env,
+ orig_env,
+ &mut fresh_preds,
+ false,
+ ) else {
+ return AutoTraitResult::NegativeImpl;
+ };
+
+ let (full_env, full_user_env) = self
+ .evaluate_predicates(
+ &infcx,
+ trait_did,
+ ty,
+ new_env,
+ user_env,
+ &mut fresh_preds,
+ true,
+ )
+ .unwrap_or_else(|| {
+ panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env)
+ });
+
+ debug!(
+ "find_auto_trait_generics({:?}): fulfilling \
+ with {:?}",
+ trait_ref, full_env
+ );
+ infcx.clear_caches();
+
+ // At this point, we already have all of the bounds we need. FulfillmentContext is used
+ // to store all of the necessary region/lifetime bounds in the InferContext, as well as
+ // an additional sanity check.
+ let mut fulfill = <dyn TraitEngine<'tcx>>::new(tcx);
+ fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
+ let errors = fulfill.select_all_or_error(&infcx);
+
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
+
+ infcx.process_registered_region_obligations(&Default::default(), full_env);
+
+ let region_data = infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .region_constraint_data()
+ .clone();
+
+ let vid_to_region = self.map_vid_to_region(&region_data);
+
+ let info = AutoTraitInfo { full_user_env, region_data, vid_to_region };
+
+ AutoTraitResult::PositiveImpl(auto_trait_callback(info))
+ })
+ }
+}
+
+impl<'tcx> AutoTraitFinder<'tcx> {
+ /// The core logic responsible for computing the bounds for our synthesized impl.
+ ///
+ /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like
+ /// `FulfillmentContext`, we recursively select the nested obligations of predicates we
+ /// encounter. However, whenever we encounter an `UnimplementedError` involving a type
+ /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular
+ /// type implements an auto trait, Unimplemented errors tell us what conditions need to be met.
+ ///
+ /// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key
+ /// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete
+ /// user code. According, it considers all possible ways that a `Predicate` could be met, which
+ /// isn't always what we want for a synthesized impl. For example, given the predicate `T:
+ /// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T:
+ /// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`,
+ /// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up.
+ /// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl
+ /// like this:
+ /// ```ignore (illustrative)
+ /// impl<T> Send for Foo<T> where T: IntoIterator
+ /// ```
+ /// While it might be technically true that Foo implements Send where `T: IntoIterator`,
+ /// the bound is overly restrictive - it's really only necessary that `T: Iterator`.
+ ///
+ /// For this reason, `evaluate_predicates` handles predicates with type variables specially.
+ /// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately
+ /// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later
+ /// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator`
+ /// needs to hold.
+ ///
+ /// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever
+ /// constructed once for a given type. As part of the construction process, the `ParamEnv` will
+ /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the
+ /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our
+ /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or
+ /// else `SelectionContext` will choke on the missing predicates. However, this should never
+ /// show up in the final synthesized generics: we don't want our generated docs page to contain
+ /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a
+ /// separate `user_env`, which only holds the predicates that will actually be displayed to the
+ /// user.
+ fn evaluate_predicates(
+ &self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ trait_did: DefId,
+ ty: Ty<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ user_env: ty::ParamEnv<'tcx>,
+ fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+ only_projections: bool,
+ ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> {
+ let tcx = infcx.tcx;
+
+ // Don't try to process any nested obligations involving predicates
+ // that are already in the `ParamEnv` (modulo regions): we already
+ // know that they must hold.
+ for predicate in param_env.caller_bounds() {
+ fresh_preds.insert(self.clean_pred(infcx, predicate));
+ }
+
+ let mut select = SelectionContext::new(&infcx);
+
+ let mut already_visited = FxHashSet::default();
+ let mut predicates = VecDeque::new();
+ predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: trait_did,
+ substs: infcx.tcx.mk_substs_trait(ty, &[]),
+ },
+ constness: ty::BoundConstness::NotConst,
+ // Auto traits are positive
+ polarity: ty::ImplPolarity::Positive,
+ }));
+
+ let computed_preds = param_env.caller_bounds().iter();
+ let mut user_computed_preds: FxHashSet<_> = user_env.caller_bounds().iter().collect();
+
+ let mut new_env = param_env;
+ let dummy_cause = ObligationCause::dummy();
+
+ while let Some(pred) = predicates.pop_front() {
+ infcx.clear_caches();
+
+ if !already_visited.insert(pred) {
+ continue;
+ }
+
+ // Call `infcx.resolve_vars_if_possible` to see if we can
+ // get rid of any inference variables.
+ let obligation =
+ infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred));
+ let result = select.select(&obligation);
+
+ match result {
+ Ok(Some(ref impl_source)) => {
+ // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`),
+ // we immediately bail out, since it's impossible for us to continue.
+
+ if let ImplSource::UserDefined(ImplSourceUserDefinedData {
+ impl_def_id, ..
+ }) = impl_source
+ {
+ // Blame 'tidy' for the weird bracket placement.
+ if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative {
+ debug!(
+ "evaluate_nested_obligations: found explicit negative impl\
+ {:?}, bailing out",
+ impl_def_id
+ );
+ return None;
+ }
+ }
+
+ let obligations = impl_source.clone().nested_obligations().into_iter();
+
+ if !self.evaluate_nested_obligations(
+ ty,
+ obligations,
+ &mut user_computed_preds,
+ fresh_preds,
+ &mut predicates,
+ &mut select,
+ only_projections,
+ ) {
+ return None;
+ }
+ }
+ Ok(None) => {}
+ Err(SelectionError::Unimplemented) => {
+ if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) {
+ already_visited.remove(&pred);
+ self.add_user_pred(&mut user_computed_preds, pred.to_predicate(self.tcx));
+ predicates.push_back(pred);
+ } else {
+ debug!(
+ "evaluate_nested_obligations: `Unimplemented` found, bailing: \
+ {:?} {:?} {:?}",
+ ty,
+ pred,
+ pred.skip_binder().trait_ref.substs
+ );
+ return None;
+ }
+ }
+ _ => panic!("Unexpected error for '{:?}': {:?}", ty, result),
+ };
+
+ let normalized_preds = elaborate_predicates(
+ tcx,
+ computed_preds.clone().chain(user_computed_preds.iter().cloned()),
+ )
+ .map(|o| o.predicate);
+ new_env = ty::ParamEnv::new(
+ tcx.mk_predicates(normalized_preds),
+ param_env.reveal(),
+ param_env.constness(),
+ );
+ }
+
+ let final_user_env = ty::ParamEnv::new(
+ tcx.mk_predicates(user_computed_preds.into_iter()),
+ user_env.reveal(),
+ user_env.constness(),
+ );
+ debug!(
+ "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \
+ '{:?}'",
+ ty, trait_did, new_env, final_user_env
+ );
+
+ Some((new_env, final_user_env))
+ }
+
+ /// This method is designed to work around the following issue:
+ /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`,
+ /// progressively building a `ParamEnv` based on the results we get.
+ /// However, our usage of `SelectionContext` differs from its normal use within the compiler,
+ /// in that we capture and re-reprocess predicates from `Unimplemented` errors.
+ ///
+ /// This can lead to a corner case when dealing with region parameters.
+ /// During our selection loop in `evaluate_predicates`, we might end up with
+ /// two trait predicates that differ only in their region parameters:
+ /// one containing a HRTB lifetime parameter, and one containing a 'normal'
+ /// lifetime parameter. For example:
+ /// ```ignore (illustrative)
+ /// T as MyTrait<'a>
+ /// T as MyTrait<'static>
+ /// ```
+ /// If we put both of these predicates in our computed `ParamEnv`, we'll
+ /// confuse `SelectionContext`, since it will (correctly) view both as being applicable.
+ ///
+ /// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB
+ /// Our end goal is to generate a user-visible description of the conditions
+ /// under which a type implements an auto trait. A trait predicate involving
+ /// a HRTB means that the type needs to work with any choice of lifetime,
+ /// not just one specific lifetime (e.g., `'static`).
+ fn add_user_pred(
+ &self,
+ user_computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+ new_pred: ty::Predicate<'tcx>,
+ ) {
+ let mut should_add_new = true;
+ user_computed_preds.retain(|&old_pred| {
+ if let (ty::PredicateKind::Trait(new_trait), ty::PredicateKind::Trait(old_trait)) =
+ (new_pred.kind().skip_binder(), old_pred.kind().skip_binder())
+ {
+ if new_trait.def_id() == old_trait.def_id() {
+ let new_substs = new_trait.trait_ref.substs;
+ let old_substs = old_trait.trait_ref.substs;
+
+ if !new_substs.types().eq(old_substs.types()) {
+ // We can't compare lifetimes if the types are different,
+ // so skip checking `old_pred`.
+ return true;
+ }
+
+ for (new_region, old_region) in
+ iter::zip(new_substs.regions(), old_substs.regions())
+ {
+ match (*new_region, *old_region) {
+ // If both predicates have an `ReLateBound` (a HRTB) in the
+ // same spot, we do nothing.
+ (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {}
+
+ (ty::ReLateBound(_, _), _) | (_, ty::ReVar(_)) => {
+ // One of these is true:
+ // The new predicate has a HRTB in a spot where the old
+ // predicate does not (if they both had a HRTB, the previous
+ // match arm would have executed). A HRBT is a 'stricter'
+ // bound than anything else, so we want to keep the newer
+ // predicate (with the HRBT) in place of the old predicate.
+ //
+ // OR
+ //
+ // The old predicate has a region variable where the new
+ // predicate has some other kind of region. An region
+ // variable isn't something we can actually display to a user,
+ // so we choose their new predicate (which doesn't have a region
+ // variable).
+ //
+ // In both cases, we want to remove the old predicate,
+ // from `user_computed_preds`, and replace it with the new
+ // one. Having both the old and the new
+ // predicate in a `ParamEnv` would confuse `SelectionContext`.
+ //
+ // We're currently in the predicate passed to 'retain',
+ // so we return `false` to remove the old predicate from
+ // `user_computed_preds`.
+ return false;
+ }
+ (_, ty::ReLateBound(_, _)) | (ty::ReVar(_), _) => {
+ // This is the opposite situation as the previous arm.
+ // One of these is true:
+ //
+ // The old predicate has a HRTB lifetime in a place where the
+ // new predicate does not.
+ //
+ // OR
+ //
+ // The new predicate has a region variable where the old
+ // predicate has some other type of region.
+ //
+ // We want to leave the old
+ // predicate in `user_computed_preds`, and skip adding
+ // new_pred to `user_computed_params`.
+ should_add_new = false
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ true
+ });
+
+ if should_add_new {
+ user_computed_preds.insert(new_pred);
+ }
+ }
+
+ /// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s
+ /// to each other, we match `ty::RegionVid`s to `ty::Region`s.
+ fn map_vid_to_region<'cx>(
+ &self,
+ regions: &RegionConstraintData<'cx>,
+ ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> {
+ let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default();
+ let mut finished_map = FxHashMap::default();
+
+ for constraint in regions.constraints.keys() {
+ match constraint {
+ &Constraint::VarSubVar(r1, r2) => {
+ {
+ let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
+ deps1.larger.insert(RegionTarget::RegionVid(r2));
+ }
+
+ let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
+ deps2.smaller.insert(RegionTarget::RegionVid(r1));
+ }
+ &Constraint::RegSubVar(region, vid) => {
+ {
+ let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default();
+ deps1.larger.insert(RegionTarget::RegionVid(vid));
+ }
+
+ let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
+ deps2.smaller.insert(RegionTarget::Region(region));
+ }
+ &Constraint::VarSubReg(vid, region) => {
+ finished_map.insert(vid, region);
+ }
+ &Constraint::RegSubReg(r1, r2) => {
+ {
+ let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default();
+ deps1.larger.insert(RegionTarget::Region(r2));
+ }
+
+ let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default();
+ deps2.smaller.insert(RegionTarget::Region(r1));
+ }
+ }
+ }
+
+ while !vid_map.is_empty() {
+ let target = *vid_map.keys().next().expect("Keys somehow empty");
+ let deps = vid_map.remove(&target).expect("Entry somehow missing");
+
+ for smaller in deps.smaller.iter() {
+ for larger in deps.larger.iter() {
+ match (smaller, larger) {
+ (&RegionTarget::Region(_), &RegionTarget::Region(_)) => {
+ if let Entry::Occupied(v) = vid_map.entry(*smaller) {
+ let smaller_deps = v.into_mut();
+ smaller_deps.larger.insert(*larger);
+ smaller_deps.larger.remove(&target);
+ }
+
+ if let Entry::Occupied(v) = vid_map.entry(*larger) {
+ let larger_deps = v.into_mut();
+ larger_deps.smaller.insert(*smaller);
+ larger_deps.smaller.remove(&target);
+ }
+ }
+ (&RegionTarget::RegionVid(v1), &RegionTarget::Region(r1)) => {
+ finished_map.insert(v1, r1);
+ }
+ (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => {
+ // Do nothing; we don't care about regions that are smaller than vids.
+ }
+ (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => {
+ if let Entry::Occupied(v) = vid_map.entry(*smaller) {
+ let smaller_deps = v.into_mut();
+ smaller_deps.larger.insert(*larger);
+ smaller_deps.larger.remove(&target);
+ }
+
+ if let Entry::Occupied(v) = vid_map.entry(*larger) {
+ let larger_deps = v.into_mut();
+ larger_deps.smaller.insert(*smaller);
+ larger_deps.smaller.remove(&target);
+ }
+ }
+ }
+ }
+ }
+ }
+ finished_map
+ }
+
+ fn is_param_no_infer(&self, substs: SubstsRef<'_>) -> bool {
+ self.is_of_param(substs.type_at(0)) && !substs.types().any(|t| t.has_infer_types())
+ }
+
+ pub fn is_of_param(&self, ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ ty::Param(_) => true,
+ ty::Projection(p) => self.is_of_param(p.self_ty()),
+ _ => false,
+ }
+ }
+
+ fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
+ if let Term::Ty(ty) = p.term().skip_binder() {
+ matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
+ } else {
+ false
+ }
+ }
+
+ fn evaluate_nested_obligations(
+ &self,
+ ty: Ty<'_>,
+ nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>,
+ computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+ fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
+ predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
+ select: &mut SelectionContext<'_, 'tcx>,
+ only_projections: bool,
+ ) -> bool {
+ let dummy_cause = ObligationCause::dummy();
+
+ for obligation in nested {
+ let is_new_pred =
+ fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate));
+
+ // Resolve any inference variables that we can, to help selection succeed
+ let predicate = select.infcx().resolve_vars_if_possible(obligation.predicate);
+
+ // We only add a predicate as a user-displayable bound if
+ // it involves a generic parameter, and doesn't contain
+ // any inference variables.
+ //
+ // Displaying a bound involving a concrete type (instead of a generic
+ // parameter) would be pointless, since it's always true
+ // (e.g. u8: Copy)
+ // Displaying an inference variable is impossible, since they're
+ // an internal compiler detail without a defined visual representation
+ //
+ // We check this by calling is_of_param on the relevant types
+ // from the various possible predicates
+
+ let bound_predicate = predicate.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(p) => {
+ // Add this to `predicates` so that we end up calling `select`
+ // with it. If this predicate ends up being unimplemented,
+ // then `evaluate_predicates` will handle adding it the `ParamEnv`
+ // if possible.
+ predicates.push_back(bound_predicate.rebind(p));
+ }
+ ty::PredicateKind::Projection(p) => {
+ let p = bound_predicate.rebind(p);
+ debug!(
+ "evaluate_nested_obligations: examining projection predicate {:?}",
+ predicate
+ );
+
+ // As described above, we only want to display
+ // bounds which include a generic parameter but don't include
+ // an inference variable.
+ // Additionally, we check if we've seen this predicate before,
+ // to avoid rendering duplicate bounds to the user.
+ if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
+ && !p.term().skip_binder().has_infer_types()
+ && is_new_pred
+ {
+ debug!(
+ "evaluate_nested_obligations: adding projection predicate \
+ to computed_preds: {:?}",
+ predicate
+ );
+
+ // Under unusual circumstances, we can end up with a self-referential
+ // projection predicate. For example:
+ // <T as MyType>::Value == <T as MyType>::Value
+ // Not only is displaying this to the user pointless,
+ // having it in the ParamEnv will cause an issue if we try to call
+ // poly_project_and_unify_type on the predicate, since this kind of
+ // predicate will normally never end up in a ParamEnv.
+ //
+ // For these reasons, we ignore these weird predicates,
+ // ensuring that we're able to properly synthesize an auto trait impl
+ if self.is_self_referential_projection(p) {
+ debug!(
+ "evaluate_nested_obligations: encountered a projection
+ predicate equating a type with itself! Skipping"
+ );
+ } else {
+ self.add_user_pred(computed_preds, predicate);
+ }
+ }
+
+ // There are three possible cases when we project a predicate:
+ //
+ // 1. We encounter an error. This means that it's impossible for
+ // our current type to implement the auto trait - there's bound
+ // that we could add to our ParamEnv that would 'fix' this kind
+ // of error, as it's not caused by an unimplemented type.
+ //
+ // 2. We successfully project the predicate (Ok(Some(_))), generating
+ // some subobligations. We then process these subobligations
+ // like any other generated sub-obligations.
+ //
+ // 3. We receive an 'ambiguous' result (Ok(None))
+ // If we were actually trying to compile a crate,
+ // we would need to re-process this obligation later.
+ // However, all we care about is finding out what bounds
+ // are needed for our type to implement a particular auto trait.
+ // We've already added this obligation to our computed ParamEnv
+ // above (if it was necessary). Therefore, we don't need
+ // to do any further processing of the obligation.
+ //
+ // Note that we *must* try to project *all* projection predicates
+ // we encounter, even ones without inference variable.
+ // This ensures that we detect any projection errors,
+ // which indicate that our type can *never* implement the given
+ // auto trait. In that case, we will generate an explicit negative
+ // impl (e.g. 'impl !Send for MyType'). However, we don't
+ // try to process any of the generated subobligations -
+ // they contain no new information, since we already know
+ // that our type implements the projected-through trait,
+ // and can lead to weird region issues.
+ //
+ // Normally, we'll generate a negative impl as a result of encountering
+ // a type with an explicit negative impl of an auto trait
+ // (for example, raw pointers have !Send and !Sync impls)
+ // However, through some **interesting** manipulations of the type
+ // system, it's actually possible to write a type that never
+ // implements an auto trait due to a projection error, not a normal
+ // negative impl error. To properly handle this case, we need
+ // to ensure that we catch any potential projection errors,
+ // and turn them into an explicit negative impl for our type.
+ debug!("Projecting and unifying projection predicate {:?}", predicate);
+
+ match project::poly_project_and_unify_type(select, &obligation.with(p)) {
+ ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
+ debug!(
+ "evaluate_nested_obligations: Unable to unify predicate \
+ '{:?}' '{:?}', bailing out",
+ ty, e
+ );
+ return false;
+ }
+ ProjectAndUnifyResult::Recursive => {
+ debug!("evaluate_nested_obligations: recursive projection predicate");
+ return false;
+ }
+ ProjectAndUnifyResult::Holds(v) => {
+ // We only care about sub-obligations
+ // when we started out trying to unify
+ // some inference variables. See the comment above
+ // for more information
+ if p.term().skip_binder().has_infer_types() {
+ if !self.evaluate_nested_obligations(
+ ty,
+ v.into_iter(),
+ computed_preds,
+ fresh_preds,
+ predicates,
+ select,
+ only_projections,
+ ) {
+ return false;
+ }
+ }
+ }
+ ProjectAndUnifyResult::FailedNormalization => {
+ // It's ok not to make progress when have no inference variables -
+ // in that case, we were only performing unification to check if an
+ // error occurred (which would indicate that it's impossible for our
+ // type to implement the auto trait).
+ // However, we should always make progress (either by generating
+ // subobligations or getting an error) when we started off with
+ // inference variables
+ if p.term().skip_binder().has_infer_types() {
+ panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
+ }
+ }
+ }
+ }
+ ty::PredicateKind::RegionOutlives(binder) => {
+ let binder = bound_predicate.rebind(binder);
+ select.infcx().region_outlives_predicate(&dummy_cause, binder)
+ }
+ ty::PredicateKind::TypeOutlives(binder) => {
+ let binder = bound_predicate.rebind(binder);
+ match (
+ binder.no_bound_vars(),
+ binder.map_bound_ref(|pred| pred.0).no_bound_vars(),
+ ) {
+ (None, Some(t_a)) => {
+ select.infcx().register_region_obligation_with_cause(
+ t_a,
+ select.infcx().tcx.lifetimes.re_static,
+ &dummy_cause,
+ );
+ }
+ (Some(ty::OutlivesPredicate(t_a, r_b)), _) => {
+ select.infcx().register_region_obligation_with_cause(
+ t_a,
+ r_b,
+ &dummy_cause,
+ );
+ }
+ _ => {}
+ };
+ }
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ let evaluate = |c: ty::Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+ match select.infcx().const_eval_resolve(
+ obligation.param_env,
+ unevaluated,
+ Some(obligation.cause.span),
+ ) {
+ Ok(Some(valtree)) => {
+ Ok(ty::Const::from_value(select.tcx(), valtree, c.ty()))
+ }
+ Ok(None) => {
+ let tcx = self.tcx;
+ let def_id = unevaluated.def.did;
+ let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit();
+
+ Err(ErrorHandled::Reported(reported))
+ }
+ Err(err) => Err(err),
+ }
+ } else {
+ Ok(c)
+ }
+ };
+
+ match (evaluate(c1), evaluate(c2)) {
+ (Ok(c1), Ok(c2)) => {
+ match select
+ .infcx()
+ .at(&obligation.cause, obligation.param_env)
+ .eq(c1, c2)
+ {
+ Ok(_) => (),
+ Err(_) => return false,
+ }
+ }
+ _ => return false,
+ }
+ }
+ // There's not really much we can do with these predicates -
+ // we start out with a `ParamEnv` with no inference variables,
+ // and these don't correspond to adding any new bounds to
+ // the `ParamEnv`.
+ ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+ };
+ }
+ true
+ }
+
+ pub fn clean_pred(
+ &self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ p: ty::Predicate<'tcx>,
+ ) -> ty::Predicate<'tcx> {
+ infcx.freshen(p)
+ }
+}
+
+// Replaces all ReVars in a type with ty::Region's, using the provided map
+pub struct RegionReplacer<'a, 'tcx> {
+ vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ (match *r {
+ ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
+ _ => None,
+ })
+ .unwrap_or_else(|| r.super_fold_with(self))
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
new file mode 100644
index 000000000..9ef7ac9a8
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -0,0 +1,163 @@
+//! Defines a Chalk-based `TraitEngine`
+
+use crate::infer::canonical::OriginalQueryValues;
+use crate::infer::InferCtxt;
+use crate::traits::query::NoSolution;
+use crate::traits::{
+ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause,
+ PredicateObligation, SelectionError, TraitEngine,
+};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
+
+pub struct FulfillmentContext<'tcx> {
+ obligations: FxIndexSet<PredicateObligation<'tcx>>,
+
+ relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
+}
+
+impl FulfillmentContext<'_> {
+ pub(crate) fn new() -> Self {
+ FulfillmentContext {
+ obligations: FxIndexSet::default(),
+ relationships: FxHashMap::default(),
+ }
+ }
+}
+
+impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
+ fn normalize_projection_type(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ _param_env: ty::ParamEnv<'tcx>,
+ projection_ty: ty::ProjectionTy<'tcx>,
+ _cause: ObligationCause<'tcx>,
+ ) -> Ty<'tcx> {
+ infcx.tcx.mk_ty(ty::Projection(projection_ty))
+ }
+
+ fn register_predicate_obligation(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ obligation: PredicateObligation<'tcx>,
+ ) {
+ assert!(!infcx.is_in_snapshot());
+ let obligation = infcx.resolve_vars_if_possible(obligation);
+
+ super::relationships::update(self, infcx, &obligation);
+
+ self.obligations.insert(obligation);
+ }
+
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ // any remaining obligations are errors
+ self.obligations
+ .iter()
+ .map(|obligation| FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeAmbiguity,
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation.clone(),
+ })
+ .collect()
+ }
+
+ fn select_where_possible(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ ) -> Vec<FulfillmentError<'tcx>> {
+ assert!(!infcx.is_in_snapshot());
+
+ let mut errors = Vec::new();
+ let mut next_round = FxIndexSet::default();
+ let mut making_progress;
+
+ loop {
+ making_progress = false;
+
+ // We iterate over all obligations, and record if we are able
+ // to unambiguously prove at least one obligation.
+ for obligation in self.obligations.drain(..) {
+ let obligation = infcx.resolve_vars_if_possible(obligation);
+ let environment = obligation.param_env.caller_bounds();
+ let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
+ let mut orig_values = OriginalQueryValues::default();
+ if goal.references_error() {
+ continue;
+ }
+
+ let canonical_goal =
+ infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
+
+ match infcx.tcx.evaluate_goal(canonical_goal) {
+ Ok(response) => {
+ if response.is_proven() {
+ making_progress = true;
+
+ match infcx.instantiate_query_response_and_region_obligations(
+ &obligation.cause,
+ obligation.param_env,
+ &orig_values,
+ &response,
+ ) {
+ Ok(infer_ok) => next_round.extend(
+ infer_ok.obligations.into_iter().map(|obligation| {
+ assert!(!infcx.is_in_snapshot());
+ infcx.resolve_vars_if_possible(obligation)
+ }),
+ ),
+
+ Err(_err) => errors.push(FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeSelectionError(
+ SelectionError::Unimplemented,
+ ),
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation,
+ }),
+ }
+ } else {
+ // Ambiguous: retry at next round.
+ next_round.insert(obligation);
+ }
+ }
+
+ Err(NoSolution) => errors.push(FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeSelectionError(
+ SelectionError::Unimplemented,
+ ),
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation,
+ }),
+ }
+ }
+ next_round = std::mem::replace(&mut self.obligations, next_round);
+
+ if !making_progress {
+ break;
+ }
+ }
+
+ errors
+ }
+
+ fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+ self.obligations.iter().cloned().collect()
+ }
+
+ fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
+ &mut self.relationships
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
new file mode 100644
index 000000000..c0700748c
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -0,0 +1,80 @@
+// This file contains various trait resolution methods used by codegen.
+// They all assume regions can be erased and monomorphic types. It
+// seems likely that they should eventually be merged into more
+// general routines.
+
+use crate::infer::{DefiningAnchor, TyCtxtInferExt};
+use crate::traits::{
+ ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
+ Unimplemented,
+};
+use rustc_middle::traits::CodegenObligationError;
+use rustc_middle::ty::{self, TyCtxt};
+
+/// Attempts to resolve an obligation to an `ImplSource`. The result is
+/// a shallow `ImplSource` resolution, meaning that we do not
+/// (necessarily) resolve all nested obligations on the impl. Note
+/// that type check should guarantee to us that all nested
+/// obligations *could be* resolved if we wanted to.
+///
+/// This also expects that `trait_ref` is fully normalized.
+#[instrument(level = "debug", skip(tcx))]
+pub fn codegen_fulfill_obligation<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
+) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
+ // We expect the input to be fully normalized.
+ debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
+
+ // Do the initial selection for the obligation. This yields the
+ // shallow result we are looking for -- that is, what specific impl.
+ let mut infcx_builder =
+ tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
+ infcx_builder.enter(|infcx| {
+ //~^ HACK `Bubble` is required for
+ // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs
+ let mut selcx = SelectionContext::new(&infcx);
+
+ let obligation_cause = ObligationCause::dummy();
+ let obligation =
+ Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate());
+
+ let selection = match selcx.select(&obligation) {
+ Ok(Some(selection)) => selection,
+ Ok(None) => return Err(CodegenObligationError::Ambiguity),
+ Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
+ Err(e) => {
+ bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
+ }
+ };
+
+ debug!(?selection);
+
+ // Currently, we use a fulfillment context to completely resolve
+ // all nested obligations. This is because they can inform the
+ // inference of the impl's type parameters.
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
+ let impl_source = selection.map(|predicate| {
+ fulfill_cx.register_predicate_obligation(&infcx, predicate);
+ });
+
+ // In principle, we only need to do this so long as `impl_source`
+ // contains unbound type parameters. It could be a slight
+ // optimization to stop iterating early.
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ return Err(CodegenObligationError::FulfillmentError);
+ }
+
+ let impl_source = infcx.resolve_vars_if_possible(impl_source);
+ let impl_source = infcx.tcx.erase_regions(impl_source);
+
+ // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
+ // as they will get constrained elsewhere, too.
+ // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
+ debug!("Cache miss: {trait_ref:?} => {impl_source:?}");
+ Ok(&*tcx.arena.alloc(impl_source))
+ })
+}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
new file mode 100644
index 000000000..1c8cdf4ca
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -0,0 +1,747 @@
+//! See Rustc Dev Guide chapters on [trait-resolution] and [trait-specialization] for more info on
+//! how this works.
+//!
+//! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
+//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
+
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::{CombinedSnapshot, InferOk};
+use crate::traits::select::IntercrateAmbiguityCause;
+use crate::traits::util::impl_subject_and_oblig;
+use crate::traits::SkipLeakCheck;
+use crate::traits::{
+ self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
+ PredicateObligations, SelectionContext, TraitEngineExt,
+};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_errors::Diagnostic;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_infer::traits::{util, TraitEngine};
+use rustc_middle::traits::specialization_graph::OverlapMode;
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
+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
+/// to some remote crate.
+#[derive(Copy, Clone, Debug)]
+enum InCrate {
+ Local,
+ Remote,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum Conflict {
+ Upstream,
+ Downstream,
+}
+
+pub struct OverlapResult<'tcx> {
+ pub impl_header: ty::ImplHeader<'tcx>,
+ pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
+
+ /// `true` if the overlap might've been permitted before the shift
+ /// to universes.
+ pub involves_placeholder: bool,
+}
+
+pub fn add_placeholder_note(err: &mut Diagnostic) {
+ err.note(
+ "this behavior recently changed as a result of a bug fix; \
+ see rust-lang/rust#56105 for details",
+ );
+}
+
+/// If there are types that satisfy both impls, invokes `on_overlap`
+/// with a suitably-freshened `ImplHeader` with those types
+/// substituted. Otherwise, invokes `no_overlap`.
+#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
+pub fn overlapping_impls<F1, F2, R>(
+ tcx: TyCtxt<'_>,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ skip_leak_check: SkipLeakCheck,
+ overlap_mode: OverlapMode,
+ on_overlap: F1,
+ no_overlap: F2,
+) -> R
+where
+ F1: FnOnce(OverlapResult<'_>) -> R,
+ F2: FnOnce() -> R,
+{
+ // Before doing expensive operations like entering an inference context, do
+ // a quick check via fast_reject to tell if the impl headers could possibly
+ // unify.
+ let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
+ let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
+ let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
+ let may_overlap = match (impl1_ref, impl2_ref) {
+ (Some(a), Some(b)) => iter::zip(a.substs, b.substs)
+ .all(|(arg1, arg2)| drcx.generic_args_may_unify(arg1, arg2)),
+ (None, None) => {
+ let self_ty1 = tcx.type_of(impl1_def_id);
+ let self_ty2 = tcx.type_of(impl2_def_id);
+ drcx.types_may_unify(self_ty1, self_ty2)
+ }
+ _ => bug!("unexpected impls: {impl1_def_id:?} {impl2_def_id:?}"),
+ };
+
+ if !may_overlap {
+ // Some types involved are definitely different, so the impls couldn't possibly overlap.
+ debug!("overlapping_impls: fast_reject early-exit");
+ return no_overlap();
+ }
+
+ let overlaps = tcx.infer_ctxt().enter(|infcx| {
+ let selcx = &mut SelectionContext::intercrate(&infcx);
+ overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).is_some()
+ });
+
+ if !overlaps {
+ return no_overlap();
+ }
+
+ // In the case where we detect an error, run the check again, but
+ // this time tracking intercrate ambiguity causes for better
+ // diagnostics. (These take time and can lead to false errors.)
+ tcx.infer_ctxt().enter(|infcx| {
+ let selcx = &mut SelectionContext::intercrate(&infcx);
+ selcx.enable_tracking_intercrate_ambiguity_causes();
+ on_overlap(
+ overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id, overlap_mode).unwrap(),
+ )
+ })
+}
+
+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_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
+
+ let header = ty::ImplHeader {
+ impl_def_id,
+ self_ty: tcx.bound_type_of(impl_def_id).subst(tcx, impl_substs),
+ trait_ref: tcx.bound_impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
+ predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
+ };
+
+ let Normalized { value: mut header, obligations } =
+ traits::normalize(selcx, param_env, ObligationCause::dummy(), header);
+
+ header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
+ header
+}
+
+/// Can both impl `a` and impl `b` be satisfied by a common type (including
+/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls.
+fn overlap<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ skip_leak_check: SkipLeakCheck,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ overlap_mode: OverlapMode,
+) -> Option<OverlapResult<'tcx>> {
+ debug!(
+ "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})",
+ impl1_def_id, impl2_def_id, overlap_mode
+ );
+
+ selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
+ overlap_within_probe(selcx, impl1_def_id, impl2_def_id, overlap_mode, snapshot)
+ })
+}
+
+fn overlap_within_probe<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ overlap_mode: OverlapMode,
+ snapshot: &CombinedSnapshot<'_, 'tcx>,
+) -> Option<OverlapResult<'tcx>> {
+ let infcx = selcx.infcx();
+
+ if overlap_mode.use_negative_impl() {
+ if negative_impl(selcx, impl1_def_id, impl2_def_id)
+ || negative_impl(selcx, impl2_def_id, impl1_def_id)
+ {
+ return None;
+ }
+ }
+
+ // For the purposes of this check, we don't bring any placeholder
+ // types into scope; instead, we replace the generic types with
+ // fresh type variables, and hence we do our evaluations in an
+ // 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 obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
+ debug!("overlap: unification check succeeded");
+
+ if overlap_mode.use_implicit_negative() {
+ if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) {
+ return None;
+ }
+ }
+
+ // We disable the leak when when creating the `snapshot` by using
+ // `infcx.probe_maybe_disable_leak_check`.
+ if infcx.leak_check(true, snapshot).is_err() {
+ debug!("overlap: leak check failed");
+ return None;
+ }
+
+ let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+ debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+
+ let involves_placeholder =
+ matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
+
+ let impl_header = selcx.infcx().resolve_vars_if_possible(impl1_header);
+ Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
+}
+
+fn equate_impl_headers<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ impl1_header: &ty::ImplHeader<'tcx>,
+ impl2_header: &ty::ImplHeader<'tcx>,
+) -> Option<PredicateObligations<'tcx>> {
+ // Do `a` and `b` unify? If not, no overlap.
+ debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
+ selcx
+ .infcx()
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .eq_impl_headers(impl1_header, impl2_header)
+ .map(|infer_ok| infer_ok.obligations)
+ .ok()
+}
+
+/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
+/// where-clauses) If so, return false, otherwise return true, they are disjoint.
+fn implicit_negative<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ impl1_header: &ty::ImplHeader<'tcx>,
+ impl2_header: ty::ImplHeader<'tcx>,
+ obligations: PredicateObligations<'tcx>,
+) -> bool {
+ // There's no overlap if obligations are unsatisfiable or if the obligation negated is
+ // satisfied.
+ //
+ // For example, given these two impl headers:
+ //
+ // `impl<'a> From<&'a str> for Box<dyn Error>`
+ // `impl<E> From<E> for Box<dyn Error> where E: Error`
+ //
+ // So we have:
+ //
+ // `Box<dyn Error>: From<&'?a str>`
+ // `Box<dyn Error>: From<?E>`
+ //
+ // After equating the two headers:
+ //
+ // `Box<dyn Error> = Box<dyn Error>`
+ // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
+ //
+ // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
+ // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
+ // at some point an impl for `&'?a str: Error` could be added.
+ debug!(
+ "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})",
+ impl1_header, impl2_header, obligations
+ );
+ let infcx = selcx.infcx();
+ let opt_failing_obligation = impl1_header
+ .predicates
+ .iter()
+ .copied()
+ .chain(impl2_header.predicates)
+ .map(|p| infcx.resolve_vars_if_possible(p))
+ .map(|p| Obligation {
+ cause: ObligationCause::dummy(),
+ param_env,
+ recursion_depth: 0,
+ predicate: p,
+ })
+ .chain(obligations)
+ .find(|o| !selcx.predicate_may_hold_fatal(o));
+
+ if let Some(failing_obligation) = opt_failing_obligation {
+ debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
+ true
+ } else {
+ false
+ }
+}
+
+/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
+/// where-clauses) If so, return true, they are disjoint and false otherwise.
+fn negative_impl<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+) -> bool {
+ debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
+ let tcx = selcx.infcx().tcx;
+
+ // Create an infcx, taking the predicates of impl1 as assumptions:
+ tcx.infer_ctxt().enter(|infcx| {
+ // 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,
+ FulfillmentContext::new(),
+ ObligationCause::dummy(),
+ impl_env,
+ tcx.impl_subject(impl1_def_id),
+ ) {
+ Ok(s) => s,
+ Err(err) => bug!("failed to fully normalize {:?}: {:?}", impl1_def_id, err),
+ };
+
+ // Attempt to prove that impl2 applies, given all of the above.
+ let selcx = &mut SelectionContext::new(&infcx);
+ let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
+ let (subject2, obligations) =
+ impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
+
+ !equate(&infcx, impl_env, subject1, subject2, obligations)
+ })
+}
+
+fn equate<'cx, 'tcx>(
+ infcx: &InferCtxt<'cx, 'tcx>,
+ impl_env: ty::ParamEnv<'tcx>,
+ subject1: ImplSubject<'tcx>,
+ subject2: ImplSubject<'tcx>,
+ obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
+) -> bool {
+ // do the impls unify? If not, not disjoint.
+ let Ok(InferOk { obligations: more_obligations, .. }) =
+ infcx.at(&ObligationCause::dummy(), impl_env).eq(subject1, subject2)
+ else {
+ debug!("explicit_disjoint: {:?} does not unify with {:?}", subject1, subject2);
+ return true;
+ };
+
+ let selcx = &mut SelectionContext::new(&infcx);
+ let opt_failing_obligation = obligations
+ .into_iter()
+ .chain(more_obligations)
+ .find(|o| negative_impl_exists(selcx, impl_env, o));
+
+ if let Some(failing_obligation) = opt_failing_obligation {
+ debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
+ false
+ } else {
+ true
+ }
+}
+
+/// Try to prove that a negative impl exist for the given obligation and its super predicates.
+#[instrument(level = "debug", skip(selcx))]
+fn negative_impl_exists<'cx, 'tcx>(
+ selcx: &SelectionContext<'cx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ o: &PredicateObligation<'tcx>,
+) -> bool {
+ let infcx = &selcx.infcx().fork();
+
+ if resolve_negative_obligation(infcx, param_env, o) {
+ return true;
+ }
+
+ // Try to prove a negative obligation exists for super predicates
+ for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
+ if resolve_negative_obligation(infcx, param_env, &o) {
+ return true;
+ }
+ }
+
+ false
+}
+
+#[instrument(level = "debug", skip(infcx))]
+fn resolve_negative_obligation<'cx, 'tcx>(
+ infcx: &InferCtxt<'cx, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ o: &PredicateObligation<'tcx>,
+) -> bool {
+ let tcx = infcx.tcx;
+
+ let Some(o) = o.flip_polarity(tcx) else {
+ return false;
+ };
+
+ let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ fulfillment_cx.register_predicate_obligation(infcx, o);
+
+ let errors = fulfillment_cx.select_all_or_error(infcx);
+
+ if !errors.is_empty() {
+ return false;
+ }
+
+ // FIXME -- also add "assumed to be well formed" types into the `outlives_env`
+ let outlives_env = OutlivesEnvironment::new(param_env);
+ infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
+
+ infcx.resolve_regions(&outlives_env).is_empty()
+}
+
+pub fn trait_ref_is_knowable<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+) -> Option<Conflict> {
+ debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
+ if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() {
+ // A downstream or cousin crate is allowed to implement some
+ // substitution of this trait-ref.
+ return Some(Conflict::Downstream);
+ }
+
+ if trait_ref_is_local_or_fundamental(tcx, trait_ref) {
+ // This is a local or fundamental trait, so future-compatibility
+ // is no concern. We know that downstream/cousin crates are not
+ // allowed to implement a substitution of this trait ref, which
+ // means impls could only come from dependencies of this crate,
+ // which we already know about.
+ return None;
+ }
+
+ // This is a remote non-fundamental trait, so if another crate
+ // can be the "final owner" of a substitution of this trait-ref,
+ // they are allowed to implement it future-compatibly.
+ //
+ // However, if we are a final owner, then nobody else can be,
+ // and if we are an intermediate owner, then we don't care
+ // about future-compatibility, which means that we're OK if
+ // we are an owner.
+ if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() {
+ debug!("trait_ref_is_knowable: orphan check passed");
+ None
+ } else {
+ debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned");
+ Some(Conflict::Upstream)
+ }
+}
+
+pub fn trait_ref_is_local_or_fundamental<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+) -> bool {
+ trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental)
+}
+
+pub enum OrphanCheckErr<'tcx> {
+ NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>),
+ UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>),
+}
+
+/// Checks the coherence orphan rules. `impl_def_id` should be the
+/// `DefId` of a trait impl. To pass, either the trait must be local, or else
+/// two conditions must be satisfied:
+///
+/// 1. All type parameters in `Self` must be "covered" by some local type constructor.
+/// 2. Some local type must appear in `Self`.
+pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> {
+ debug!("orphan_check({:?})", impl_def_id);
+
+ // We only except this routine to be invoked on implementations
+ // of a trait, not inherent implementations.
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ debug!("orphan_check: trait_ref={:?}", trait_ref);
+
+ // If the *trait* is local to the crate, ok.
+ if trait_ref.def_id.is_local() {
+ debug!("trait {:?} is local to current crate", trait_ref.def_id);
+ return Ok(());
+ }
+
+ orphan_check_trait_ref(tcx, trait_ref, InCrate::Local)
+}
+
+/// Checks whether a trait-ref is potentially implementable by a crate.
+///
+/// The current rule is that a trait-ref orphan checks in a crate C:
+///
+/// 1. Order the parameters in the trait-ref in subst order - Self first,
+/// others linearly (e.g., `<U as Foo<V, W>>` is U < V < W).
+/// 2. Of these type parameters, there is at least one type parameter
+/// in which, walking the type as a tree, you can reach a type local
+/// to C where all types in-between are fundamental types. Call the
+/// first such parameter the "local key parameter".
+/// - e.g., `Box<LocalType>` is OK, because you can visit LocalType
+/// going through `Box`, which is fundamental.
+/// - similarly, `FundamentalPair<Vec<()>, Box<LocalType>>` is OK for
+/// the same reason.
+/// - but (knowing that `Vec<T>` is non-fundamental, and assuming it's
+/// not local), `Vec<LocalType>` is bad, because `Vec<->` is between
+/// the local type and the type parameter.
+/// 3. Before this local type, no generic type parameter of the impl must
+/// be reachable through fundamental types.
+/// - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
+/// - while `impl<T> Trait<LocalType> for Box<T>` results in an error, as `T` is
+/// reachable through the fundamental type `Box`.
+/// 4. Every type in the local key parameter not known in C, going
+/// through the parameter's type tree, must appear only as a subtree of
+/// a type local to C, with only fundamental types between the type
+/// local to C and the local key parameter.
+/// - e.g., `Vec<LocalType<T>>>` (or equivalently `Box<Vec<LocalType<T>>>`)
+/// is bad, because the only local type with `T` as a subtree is
+/// `LocalType<T>`, and `Vec<->` is between it and the type parameter.
+/// - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because
+/// the second occurrence of `T` is not a subtree of *any* local type.
+/// - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of
+/// `LocalType<Vec<T>>`, which is local and has no types between it and
+/// the type parameter.
+///
+/// The orphan rules actually serve several different purposes:
+///
+/// 1. They enable link-safety - i.e., 2 mutually-unknowing crates (where
+/// every type local to one crate is unknown in the other) can't implement
+/// the same trait-ref. This follows because it can be seen that no such
+/// type can orphan-check in 2 such crates.
+///
+/// To check that a local impl follows the orphan rules, we check it in
+/// InCrate::Local mode, using type parameters for the "generic" types.
+///
+/// 2. They ground negative reasoning for coherence. If a user wants to
+/// write both a conditional blanket impl and a specific impl, we need to
+/// make sure they do not overlap. For example, if we write
+/// ```ignore (illustrative)
+/// impl<T> IntoIterator for Vec<T>
+/// impl<T: Iterator> IntoIterator for T
+/// ```
+/// We need to be able to prove that `Vec<$0>: !Iterator` for every type $0.
+/// We can observe that this holds in the current crate, but we need to make
+/// sure this will also hold in all unknown crates (both "independent" crates,
+/// which we need for link-safety, and also child crates, because we don't want
+/// child crates to get error for impl conflicts in a *dependency*).
+///
+/// For that, we only allow negative reasoning if, for every assignment to the
+/// inference variables, every unknown crate would get an orphan error if they
+/// try to implement this trait-ref. To check for this, we use InCrate::Remote
+/// mode. That is sound because we already know all the impls from known crates.
+///
+/// 3. For non-`#[fundamental]` traits, they guarantee that parent crates can
+/// add "non-blanket" impls without breaking negative reasoning in dependent
+/// crates. This is the "rebalancing coherence" (RFC 1023) restriction.
+///
+/// For that, we only a allow crate to perform negative reasoning on
+/// non-local-non-`#[fundamental]` only if there's a local key parameter as per (2).
+///
+/// Because we never perform negative reasoning generically (coherence does
+/// not involve type parameters), this can be interpreted as doing the full
+/// orphan check (using InCrate::Local mode), substituting non-local known
+/// types for all inference variables.
+///
+/// This allows for crates to future-compatibly add impls as long as they
+/// can't apply to types with a key parameter in a child crate - applying
+/// the rules, this basically means that every type parameter in the impl
+/// must appear behind a non-fundamental type (because this is not a
+/// type-system requirement, crate owners might also go for "semantic
+/// future-compatibility" involving things such as sealed traits, but
+/// the above requirement is sufficient, and is necessary in "open world"
+/// cases).
+///
+/// Note that this function is never called for types that have both type
+/// parameters and inference variables.
+fn orphan_check_trait_ref<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ in_crate: InCrate,
+) -> Result<(), OrphanCheckErr<'tcx>> {
+ debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
+
+ if trait_ref.needs_infer() && trait_ref.needs_subst() {
+ bug!(
+ "can't orphan check a trait ref with both params and inference variables {:?}",
+ trait_ref
+ );
+ }
+
+ let mut checker = OrphanChecker::new(tcx, in_crate);
+ match trait_ref.visit_with(&mut checker) {
+ ControlFlow::Continue(()) => Err(OrphanCheckErr::NonLocalInputType(checker.non_local_tys)),
+ ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(ty)) => {
+ // Does there exist some local type after the `ParamTy`.
+ checker.search_first_local_ty = true;
+ if let Some(OrphanCheckEarlyExit::LocalTy(local_ty)) =
+ trait_ref.visit_with(&mut checker).break_value()
+ {
+ Err(OrphanCheckErr::UncoveredTy(ty, Some(local_ty)))
+ } else {
+ Err(OrphanCheckErr::UncoveredTy(ty, None))
+ }
+ }
+ ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(_)) => Ok(()),
+ }
+}
+
+struct OrphanChecker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ in_crate: InCrate,
+ in_self_ty: bool,
+ /// Ignore orphan check failures and exclusively search for the first
+ /// local type.
+ search_first_local_ty: bool,
+ non_local_tys: Vec<(Ty<'tcx>, bool)>,
+}
+
+impl<'tcx> OrphanChecker<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, in_crate: InCrate) -> Self {
+ OrphanChecker {
+ tcx,
+ in_crate,
+ in_self_ty: true,
+ search_first_local_ty: false,
+ non_local_tys: Vec::new(),
+ }
+ }
+
+ fn found_non_local_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
+ self.non_local_tys.push((t, self.in_self_ty));
+ ControlFlow::CONTINUE
+ }
+
+ fn found_param_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<OrphanCheckEarlyExit<'tcx>> {
+ if self.search_first_local_ty {
+ ControlFlow::CONTINUE
+ } else {
+ ControlFlow::Break(OrphanCheckEarlyExit::ParamTy(t))
+ }
+ }
+
+ fn def_id_is_local(&mut self, def_id: DefId) -> bool {
+ match self.in_crate {
+ InCrate::Local => def_id.is_local(),
+ InCrate::Remote => false,
+ }
+ }
+}
+
+enum OrphanCheckEarlyExit<'tcx> {
+ ParamTy(Ty<'tcx>),
+ LocalTy(Ty<'tcx>),
+}
+
+impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
+ type BreakTy = OrphanCheckEarlyExit<'tcx>;
+ fn visit_region(&mut self, _r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let result = match *ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(..)
+ | ty::Uint(..)
+ | ty::Float(..)
+ | ty::Str
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Array(..)
+ | ty::Slice(..)
+ | ty::RawPtr(..)
+ | ty::Never
+ | ty::Tuple(..)
+ | ty::Projection(..) => self.found_non_local_ty(ty),
+
+ ty::Param(..) => self.found_param_ty(ty),
+
+ ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match self.in_crate {
+ InCrate::Local => self.found_non_local_ty(ty),
+ // The inference variable might be unified with a local
+ // type in that remote crate.
+ InCrate::Remote => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+ },
+
+ // For fundamental types, we just look inside of them.
+ ty::Ref(_, ty, _) => ty.visit_with(self),
+ ty::Adt(def, substs) => {
+ if self.def_id_is_local(def.did()) {
+ ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+ } else if def.is_fundamental() {
+ substs.visit_with(self)
+ } else {
+ self.found_non_local_ty(ty)
+ }
+ }
+ ty::Foreign(def_id) => {
+ if self.def_id_is_local(def_id) {
+ ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+ } else {
+ self.found_non_local_ty(ty)
+ }
+ }
+ ty::Dynamic(tt, ..) => {
+ let principal = tt.principal().map(|p| p.def_id());
+ if principal.map_or(false, |p| self.def_id_is_local(p)) {
+ ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+ } else {
+ self.found_non_local_ty(ty)
+ }
+ }
+ ty::Error(_) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)),
+ ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
+ self.tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("ty_is_local invoked on closure or generator: {:?}", ty),
+ );
+ ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
+ }
+ ty::Opaque(..) => {
+ // This merits some explanation.
+ // Normally, opaque types are not involved when performing
+ // coherence checking, since it is illegal to directly
+ // implement a trait on an opaque type. However, we might
+ // end up looking at an opaque type during coherence checking
+ // if an opaque type gets used within another type (e.g. as
+ // the type of a field) when checking for auto trait or `Sized`
+ // impls. This requires us to decide whether or not an opaque
+ // type should be considered 'local' or not.
+ //
+ // We choose to treat all opaque types as non-local, even
+ // those that appear within the same crate. This seems
+ // somewhat surprising at first, but makes sense when
+ // you consider that opaque types are supposed to hide
+ // the underlying type *within the same crate*. When an
+ // opaque type is used from outside the module
+ // where it is declared, it should be impossible to observe
+ // anything about it other than the traits that it implements.
+ //
+ // The alternative would be to look at the underlying type
+ // to determine whether or not the opaque type itself should
+ // be considered local. However, this could make it a breaking change
+ // to switch the underlying ('defining') type from a local type
+ // to a remote type. This would violate the rule that opaque
+ // types should be completely opaque apart from the traits
+ // that they implement, so we don't use this behavior.
+ self.found_non_local_ty(ty)
+ }
+ };
+ // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so
+ // the first type we visit is always the self type.
+ self.in_self_ty = false;
+ result
+ }
+
+ // FIXME: Constants should participate in orphan checking.
+ fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ ControlFlow::CONTINUE
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
new file mode 100644
index 000000000..254bc4ab6
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -0,0 +1,308 @@
+//! Checking that constant values used in types can be successfully evaluated.
+//!
+//! For concrete constants, this is fairly simple as we can just try and evaluate it.
+//!
+//! When dealing with polymorphic constants, for example `std::mem::size_of::<T>() - 1`,
+//! this is not as easy.
+//!
+//! In this case we try to build an abstract representation of this constant using
+//! `thir_abstract_const` which can then be checked for structural equality with other
+//! generic constants mentioned in the `caller_bounds` of the current environment.
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::abstract_const::{
+ walk_abstract_const, AbstractConst, FailureKind, Node, NotConstEvaluatable,
+};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
+use rustc_session::lint;
+use rustc_span::Span;
+
+use std::iter;
+use std::ops::ControlFlow;
+
+pub struct ConstUnifyCtxt<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+ pub param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> ConstUnifyCtxt<'tcx> {
+ // Substitutes generics repeatedly to allow AbstractConsts to unify where a
+ // ConstKind::Unevaluated could be turned into an AbstractConst that would unify e.g.
+ // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
+ #[inline]
+ #[instrument(skip(self), level = "debug")]
+ fn try_replace_substs_in_root(
+ &self,
+ mut abstr_const: AbstractConst<'tcx>,
+ ) -> Option<AbstractConst<'tcx>> {
+ while let Node::Leaf(ct) = abstr_const.root(self.tcx) {
+ match AbstractConst::from_const(self.tcx, ct) {
+ Ok(Some(act)) => abstr_const = act,
+ Ok(None) => break,
+ Err(_) => return None,
+ }
+ }
+
+ Some(abstr_const)
+ }
+
+ /// Tries to unify two abstract constants using structural equality.
+ #[instrument(skip(self), level = "debug")]
+ pub fn try_unify(&self, a: AbstractConst<'tcx>, b: AbstractConst<'tcx>) -> bool {
+ let a = if let Some(a) = self.try_replace_substs_in_root(a) {
+ a
+ } else {
+ return true;
+ };
+
+ let b = if let Some(b) = self.try_replace_substs_in_root(b) {
+ b
+ } else {
+ return true;
+ };
+
+ let a_root = a.root(self.tcx);
+ let b_root = b.root(self.tcx);
+ debug!(?a_root, ?b_root);
+
+ match (a_root, b_root) {
+ (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
+ let a_ct = a_ct.eval(self.tcx, self.param_env);
+ debug!("a_ct evaluated: {:?}", a_ct);
+ let b_ct = b_ct.eval(self.tcx, self.param_env);
+ debug!("b_ct evaluated: {:?}", b_ct);
+
+ if a_ct.ty() != b_ct.ty() {
+ return false;
+ }
+
+ match (a_ct.kind(), b_ct.kind()) {
+ // We can just unify errors with everything to reduce the amount of
+ // emitted errors here.
+ (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
+ (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => {
+ a_param == b_param
+ }
+ (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
+ // If we have `fn a<const N: usize>() -> [u8; N + 1]` and `fn b<const M: usize>() -> [u8; 1 + M]`
+ // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
+ // means that we only allow inference variables if they are equal.
+ (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
+ // We expand generic anonymous constants at the start of this function, so this
+ // branch should only be taking when dealing with associated constants, at
+ // which point directly comparing them seems like the desired behavior.
+ //
+ // FIXME(generic_const_exprs): This isn't actually the case.
+ // We also take this branch for concrete anonymous constants and
+ // expand generic anonymous constants with concrete substs.
+ (ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
+ a_uv == b_uv
+ }
+ // FIXME(generic_const_exprs): We may want to either actually try
+ // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
+ // this, for now we just return false here.
+ _ => false,
+ }
+ }
+ (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => {
+ self.try_unify(a.subtree(al), b.subtree(bl))
+ && self.try_unify(a.subtree(ar), b.subtree(br))
+ }
+ (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => {
+ self.try_unify(a.subtree(av), b.subtree(bv))
+ }
+ (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args))
+ if a_args.len() == b_args.len() =>
+ {
+ self.try_unify(a.subtree(a_f), b.subtree(b_f))
+ && iter::zip(a_args, b_args)
+ .all(|(&an, &bn)| self.try_unify(a.subtree(an), b.subtree(bn)))
+ }
+ (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
+ if (a_ty == b_ty) && (a_kind == b_kind) =>
+ {
+ self.try_unify(a.subtree(a_operand), b.subtree(b_operand))
+ }
+ // use this over `_ => false` to make adding variants to `Node` less error prone
+ (Node::Cast(..), _)
+ | (Node::FunctionCall(..), _)
+ | (Node::UnaryOp(..), _)
+ | (Node::Binop(..), _)
+ | (Node::Leaf(..), _) => false,
+ }
+ }
+}
+
+#[instrument(skip(tcx), level = "debug")]
+pub fn try_unify_abstract_consts<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
+ param_env: ty::ParamEnv<'tcx>,
+) -> bool {
+ (|| {
+ if let Some(a) = AbstractConst::new(tcx, a)? {
+ if let Some(b) = AbstractConst::new(tcx, b)? {
+ let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
+ return Ok(const_unify_ctxt.try_unify(a, b));
+ }
+ }
+
+ Ok(false)
+ })()
+ .unwrap_or_else(|_: ErrorGuaranteed| true)
+ // FIXME(generic_const_exprs): We should instead have this
+ // method return the resulting `ty::Const` and return `ConstKind::Error`
+ // on `ErrorGuaranteed`.
+}
+
+/// Check if a given constant can be evaluated.
+#[instrument(skip(infcx), level = "debug")]
+pub fn is_const_evaluatable<'cx, 'tcx>(
+ infcx: &InferCtxt<'cx, 'tcx>,
+ uv: ty::Unevaluated<'tcx, ()>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span,
+) -> Result<(), NotConstEvaluatable> {
+ let tcx = infcx.tcx;
+
+ if tcx.features().generic_const_exprs {
+ if let Some(ct) = AbstractConst::new(tcx, uv)? {
+ if satisfied_from_param_env(tcx, ct, param_env)? {
+ return Ok(());
+ }
+ match ct.unify_failure_kind(tcx) {
+ FailureKind::MentionsInfer => {
+ return Err(NotConstEvaluatable::MentionsInfer);
+ }
+ FailureKind::MentionsParam => {
+ return Err(NotConstEvaluatable::MentionsParam);
+ }
+ // returned below
+ FailureKind::Concrete => {}
+ }
+ }
+ let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
+ match concrete {
+ Err(ErrorHandled::TooGeneric) => {
+ Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
+ span,
+ format!("Missing value for constant, but no error reported?"),
+ )))
+ }
+ Err(ErrorHandled::Linted) => {
+ let reported = infcx
+ .tcx
+ .sess
+ .delay_span_bug(span, "constant in type had error reported as lint");
+ Err(NotConstEvaluatable::Error(reported))
+ }
+ Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+ Ok(_) => Ok(()),
+ }
+ } else {
+ // FIXME: We should only try to evaluate a given constant here if it is fully concrete
+ // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`.
+ //
+ // We previously did not check this, so we only emit a future compat warning if
+ // const evaluation succeeds and the given constant is still polymorphic for now
+ // and hopefully soon change this to an error.
+ //
+ // See #74595 for more details about this.
+ let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
+
+ match concrete {
+ // If we're evaluating a foreign constant, under a nightly compiler without generic
+ // const exprs, AND it would've passed if that expression had been evaluated with
+ // generic const exprs, then suggest using generic const exprs.
+ Err(_) if tcx.sess.is_nightly_build()
+ && let Ok(Some(ct)) = AbstractConst::new(tcx, uv)
+ && satisfied_from_param_env(tcx, ct, param_env) == Ok(true) => {
+ tcx.sess
+ .struct_span_fatal(
+ // Slightly better span than just using `span` alone
+ if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+ "failed to evaluate generic const expression",
+ )
+ .note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
+ .span_suggestion_verbose(
+ rustc_span::DUMMY_SP,
+ "consider enabling this feature",
+ "#![feature(generic_const_exprs)]\n",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
+ .emit()
+ }
+
+ Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
+ NotConstEvaluatable::MentionsInfer
+ } else if uv.has_param_types_or_consts() {
+ NotConstEvaluatable::MentionsParam
+ } else {
+ let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
+ NotConstEvaluatable::Error(guar)
+ }),
+ Err(ErrorHandled::Linted) => {
+ let reported =
+ infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
+ Err(NotConstEvaluatable::Error(reported))
+ }
+ Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+ Ok(_) => {
+ if uv.substs.has_param_types_or_consts() {
+ assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
+ let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
+
+ if mir_body.is_polymorphic {
+ let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
+ tcx.struct_span_lint_hir(
+ lint::builtin::CONST_EVALUATABLE_UNCHECKED,
+ tcx.hir().local_def_id_to_hir_id(local_def_id),
+ span,
+ |err| {
+ err.build("cannot use constants which depend on generic parameters in types").emit();
+ })
+ }
+ }
+
+ Ok(())
+ },
+ }
+ }
+}
+
+#[instrument(skip(tcx), level = "debug")]
+fn satisfied_from_param_env<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ ct: AbstractConst<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+) -> Result<bool, NotConstEvaluatable> {
+ for pred in param_env.caller_bounds() {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
+ let const_unify_ctxt = ConstUnifyCtxt { tcx, param_env };
+
+ // Try to unify with each subtree in the AbstractConst to allow for
+ // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
+ // predicate for `(N + 1) * 2`
+ let result = walk_abstract_const(tcx, b_ct, |b_ct| {
+ match const_unify_ctxt.try_unify(ct, b_ct) {
+ true => ControlFlow::BREAK,
+ false => ControlFlow::CONTINUE,
+ }
+ });
+
+ if let ControlFlow::Break(()) = result {
+ debug!("is_const_evaluatable: abstract_const ~~> ok");
+ return Ok(true);
+ }
+ }
+ }
+ _ => {} // don't care
+ }
+ }
+
+ Ok(false)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
new file mode 100644
index 000000000..6c177f638
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -0,0 +1,112 @@
+use std::cell::RefCell;
+
+use super::TraitEngine;
+use super::{ChalkFulfillmentContext, FulfillmentContext};
+use crate::infer::InferCtxtExt;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::traits::{
+ FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
+};
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub trait TraitEngineExt<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
+}
+
+impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
+ if tcx.sess.opts.unstable_opts.chalk {
+ Box::new(ChalkFulfillmentContext::new())
+ } else {
+ Box::new(FulfillmentContext::new())
+ }
+ }
+}
+
+/// Used if you want to have pleasant experience when dealing
+/// with obligations outside of hir or mir typeck.
+pub struct ObligationCtxt<'a, 'tcx> {
+ pub infcx: &'a InferCtxt<'a, 'tcx>,
+ engine: RefCell<Box<dyn TraitEngine<'tcx>>>,
+}
+
+impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
+ pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
+ Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
+ }
+
+ pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
+ self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
+ }
+
+ pub fn register_obligations(
+ &self,
+ obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+ ) {
+ // Can't use `register_predicate_obligations` because the iterator
+ // may also use this `ObligationCtxt`.
+ for obligation in obligations {
+ self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation)
+ }
+ }
+
+ pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
+ let InferOk { value, obligations } = infer_ok;
+ self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations);
+ value
+ }
+
+ /// Requires that `ty` must implement the trait with `def_id` in
+ /// the given environment. This trait must not have any type
+ /// parameters (except for `Self`).
+ pub fn register_bound(
+ &self,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ def_id: DefId,
+ ) {
+ let tcx = self.infcx.tcx;
+ let trait_ref = ty::TraitRef { def_id, substs: tcx.mk_substs_trait(ty, &[]) };
+ self.register_obligation(Obligation {
+ cause,
+ recursion_depth: 0,
+ param_env,
+ predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+ });
+ }
+
+ pub fn normalize<T: TypeFoldable<'tcx>>(
+ &self,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ ) -> T {
+ let infer_ok = self.infcx.partially_normalize_associated_types_in(cause, param_env, value);
+ self.register_infer_ok_obligations(infer_ok)
+ }
+
+ pub fn equate_types(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ ) -> Result<(), TypeError<'tcx>> {
+ match self.infcx.at(cause, param_env).eq(expected, actual) {
+ Ok(InferOk { obligations, value: () }) => {
+ self.register_obligations(obligations);
+ Ok(())
+ }
+ Err(e) => Err(e),
+ }
+ }
+
+ pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
+ self.engine.borrow_mut().select_all_or_error(self.infcx)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
new file mode 100644
index 000000000..e442c5c91
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -0,0 +1,2765 @@
+pub mod on_unimplemented;
+pub mod suggestions;
+
+use super::{
+ EvaluationResult, FulfillmentContext, FulfillmentError, FulfillmentErrorCode,
+ MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
+ OnUnimplementedDirective, OnUnimplementedNote, OutputTypeParameterMismatch, Overflow,
+ PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
+};
+
+use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{self, InferCtxt, TyCtxtInferExt};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{
+ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ MultiSpan, Style,
+};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::GenericParam;
+use rustc_hir::Item;
+use rustc_hir::Node;
+use rustc_infer::traits::TraitEngine;
+use rustc_middle::traits::select::OverflowError;
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{
+ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
+ TypeVisitable,
+};
+use rustc_span::symbol::{kw, sym};
+use rustc_span::{ExpnKind, Span, DUMMY_SP};
+use std::fmt;
+use std::iter;
+use std::ops::ControlFlow;
+
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
+use on_unimplemented::InferCtxtExt as _;
+use suggestions::InferCtxtExt as _;
+
+pub use rustc_infer::traits::error_reporting::*;
+
+// When outputting impl candidates, prefer showing those that are more similar.
+//
+// We also compare candidates after skipping lifetimes, which has a lower
+// priority than exact matches.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CandidateSimilarity {
+ Exact { ignoring_lifetimes: bool },
+ Fuzzy { ignoring_lifetimes: bool },
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct ImplCandidate<'tcx> {
+ pub trait_ref: ty::TraitRef<'tcx>,
+ pub similarity: CandidateSimilarity,
+}
+
+pub trait InferCtxtExt<'tcx> {
+ fn report_fulfillment_errors(
+ &self,
+ errors: &[FulfillmentError<'tcx>],
+ body_id: Option<hir::BodyId>,
+ fallback_has_occurred: bool,
+ ) -> ErrorGuaranteed;
+
+ fn report_overflow_error<T>(
+ &self,
+ obligation: &Obligation<'tcx, T>,
+ suggest_increasing_limit: bool,
+ ) -> !
+ where
+ T: fmt::Display + TypeFoldable<'tcx>;
+
+ fn report_overflow_error_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>,
+ fallback_has_occurred: bool,
+ );
+
+ /// 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, 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,
+ ) -> 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>>,
+ constness: ty::BoundConstness,
+ polarity: ty::ImplPolarity,
+ ) -> Result<(ty::ClosureKind, ty::Binder<'tcx, Ty<'tcx>>), ()>;
+}
+
+impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+ fn report_fulfillment_errors(
+ &self,
+ errors: &[FulfillmentError<'tcx>],
+ body_id: Option<hir::BodyId>,
+ fallback_has_occurred: bool,
+ ) -> ErrorGuaranteed {
+ #[derive(Debug)]
+ struct ErrorDescriptor<'tcx> {
+ predicate: ty::Predicate<'tcx>,
+ index: Option<usize>, // None if this is an old error
+ }
+
+ let mut error_map: FxHashMap<_, 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.map_or(false, |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 (error, suppressed) in iter::zip(errors, is_suppressed) {
+ if !suppressed {
+ self.report_fulfillment_error(error, body_id, fallback_has_occurred);
+ }
+ }
+
+ self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fullfillment 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,
+ obligation: &Obligation<'tcx, T>,
+ suggest_increasing_limit: bool,
+ ) -> !
+ where
+ T: fmt::Display + TypeFoldable<'tcx>,
+ {
+ let predicate = self.resolve_vars_if_possible(obligation.predicate.clone());
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ obligation.cause.span,
+ E0275,
+ "overflow evaluating the requirement `{}`",
+ predicate
+ );
+
+ if suggest_increasing_limit {
+ self.suggest_new_overflow_limit(&mut err);
+ }
+
+ self.note_obligation_cause_code(
+ &mut err,
+ &obligation.predicate,
+ obligation.param_env,
+ obligation.cause.code(),
+ &mut vec![],
+ &mut Default::default(),
+ );
+
+ err.emit();
+ self.tcx.sess.abort_if_errors();
+ bug!();
+ }
+
+ /// Reports that a cycle was detected which led to overflow and halts
+ /// compilation. This is equivalent to `report_overflow_error` except
+ /// that we can give a more helpful error message (and, in particular,
+ /// we do not suggest increasing the overflow limit, which is not
+ /// going to help).
+ fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! {
+ 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_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false);
+ }
+
+ fn report_selection_error(
+ &self,
+ mut obligation: PredicateObligation<'tcx>,
+ root_obligation: &PredicateObligation<'tcx>,
+ error: &SelectionError<'tcx>,
+ fallback_has_occurred: bool,
+ ) {
+ self.set_tainted_by_errors();
+ let tcx = self.tcx;
+ let mut span = obligation.cause.span;
+
+ let mut err = match *error {
+ SelectionError::Ambiguous(ref impls) => {
+ let mut err = self.tcx.sess.struct_span_err(
+ obligation.cause.span,
+ &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
+ );
+ self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
+ err.emit();
+ return;
+ }
+ 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()
+ {
+ 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;
+ }
+
+ let bound_predicate = obligation.predicate.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(trait_predicate) => {
+ let trait_predicate = bound_predicate.rebind(trait_predicate);
+ let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+
+ trait_predicate.remap_constness_diag(obligation.param_env);
+ let predicate_is_const = ty::BoundConstness::ConstIfConst
+ == trait_predicate.skip_binder().constness;
+
+ 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,
+ enclosing_scope,
+ 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(None),
+ )
+ } else {
+ (message, note, append_const_msg)
+ };
+
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0277,
+ "{}",
+ message
+ .and_then(|cannot_do_this| {
+ match (predicate_is_const, append_const_msg) {
+ // do nothing if predicate is not const
+ (false, _) => Some(cannot_do_this),
+ // suggested using default post message
+ (true, Some(None)) => {
+ Some(format!("{cannot_do_this} in const contexts"))
+ }
+ // overridden post message
+ (true, Some(Some(post_message))) => {
+ Some(format!("{cannot_do_this}{post_message}"))
+ }
+ // fallback to generic message
+ (true, None) => None,
+ }
+ })
+ .unwrap_or_else(|| format!(
+ "the trait bound `{}` is not satisfied{}",
+ trait_predicate, post_message,
+ ))
+ );
+
+ if is_try_conversion {
+ let none_error = self
+ .tcx
+ .get_diagnostic_item(sym::none_error)
+ .map(|def_id| tcx.type_of(def_id));
+ let should_convert_option_to_result =
+ Some(trait_ref.skip_binder().substs.type_at(1)) == none_error;
+ let should_convert_result_to_option =
+ Some(trait_ref.self_ty().skip_binder()) == none_error;
+ if should_convert_option_to_result {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider converting the `Option<T>` into a `Result<T, _>` \
+ using `Option::ok_or` or `Option::ok_or_else`",
+ ".ok_or_else(|| /* error value */)",
+ Applicability::HasPlaceholders,
+ );
+ } else if should_convert_result_to_option {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider converting the `Result<T, _>` into an `Option<T>` \
+ using `Result::ok`",
+ ".ok()",
+ Applicability::MachineApplicable,
+ );
+ }
+ if 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().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 = if let ObligationCauseCode::MainFunctionType =
+ obligation.cause.code()
+ {
+ "consider using `()`, or a `Result`".to_owned()
+ } else {
+ format!(
+ "{}the trait `{}` is not implemented for `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ )
+ };
+
+ 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(ref 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 {
+ err.span_label(span, explanation);
+ }
+
+ if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
+ Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+ self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
+ }
+
+ if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+ let non_const_predicate = trait_ref.without_const();
+ let non_const_obligation = Obligation {
+ cause: obligation.cause.clone(),
+ param_env: obligation.param_env.without_const(),
+ predicate: non_const_predicate.to_predicate(tcx),
+ recursion_depth: obligation.recursion_depth,
+ };
+ if self.predicate_may_hold(&non_const_obligation) {
+ err.span_note(
+ span,
+ &format!(
+ "the trait `{}` is implemented for `{}`, \
+ but that implementation is not `const`",
+ non_const_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ );
+ }
+ }
+
+ if let Some((msg, span)) = type_def {
+ err.span_label(span, &msg);
+ }
+ if let Some(ref s) = note {
+ // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
+ err.note(s.as_str());
+ }
+ if let Some(ref s) = enclosing_scope {
+ let body = tcx
+ .hir()
+ .opt_local_def_id(obligation.cause.body_id)
+ .unwrap_or_else(|| {
+ tcx.hir().body_owner_def_id(hir::BodyId {
+ hir_id: obligation.cause.body_id,
+ })
+ });
+
+ let enclosing_scope_span =
+ tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body));
+
+ err.span_label(enclosing_scope_span, 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);
+ 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_impl_trait(&mut err, span, &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 = [
+ self.tcx.lang_items().fn_trait(),
+ self.tcx.lang_items().fn_mut_trait(),
+ self.tcx.lang_items().fn_once_trait(),
+ ]
+ .contains(&Some(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",
+ );
+ }
+
+ // Try to report a help message
+ if is_fn_trait
+ && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
+ obligation.param_env,
+ trait_ref.self_ty(),
+ trait_predicate.skip_binder().constness,
+ trait_predicate.skip_binder().polarity,
+ )
+ {
+ // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
+ // suggestion to add trait bounds for the type, since we only typically implement
+ // these traits once.
+
+ // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
+ // to implement.
+ let selected_kind =
+ ty::ClosureKind::from_def_id(self.tcx, trait_ref.def_id())
+ .expect("expected to map DefId to ClosureKind");
+ if !implemented_kind.extends(selected_kind) {
+ err.note(
+ &format!(
+ "`{}` implements `{}`, but it must implement `{}`, which is more general",
+ trait_ref.skip_binder().self_ty(),
+ implemented_kind,
+ selected_kind
+ )
+ );
+ }
+
+ // Note any argument mismatches
+ let given_ty = params.skip_binder();
+ let expected_ty = trait_ref.skip_binder().substs.type_at(1);
+ if let ty::Tuple(given) = given_ty.kind()
+ && let ty::Tuple(expected) = expected_ty.kind()
+ {
+ if expected.len() != given.len() {
+ // Note number of types that were expected and given
+ err.note(
+ &format!(
+ "expected a closure taking {} argument{}, but one taking {} argument{} was given",
+ given.len(),
+ pluralize!(given.len()),
+ expected.len(),
+ pluralize!(expected.len()),
+ )
+ );
+ } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
+ // Print type mismatch
+ let (expected_args, given_args) =
+ self.cmp(given_ty, expected_ty);
+ err.note_expected_found(
+ &"a closure with arguments",
+ expected_args,
+ &"a closure with arguments",
+ given_args,
+ );
+ }
+ }
+ } else if !trait_ref.has_infer_types_or_consts()
+ && self.predicate_can_apply(obligation.param_env, trait_ref)
+ {
+ // If a where-clause may be useful, remind the
+ // user that they can add it.
+ //
+ // don't display an on-unimplemented note, as
+ // these notes will often be of the form
+ // "the type `T` can't be frobnicated"
+ // which is somewhat confusing.
+ self.suggest_restricting_param_bound(
+ &mut err,
+ trait_predicate,
+ None,
+ obligation.cause.body_id,
+ );
+ } else if !suggested {
+ // 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,
+ obligation.cause.body_id,
+ &mut err,
+ ) {
+ // 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().items().contains(&Some(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,
+ obligation.cause.body_id,
+ &mut err,
+ );
+ }
+ }
+ }
+
+ // 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()
+ && fallback_has_occurred
+ {
+ let predicate = trait_predicate.map_bound(|mut trait_pred| {
+ trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
+ self.tcx.mk_unit(),
+ &trait_pred.trait_ref.substs[1..],
+ );
+ trait_pred
+ });
+ let unit_obligation = obligation.with(predicate.to_predicate(tcx));
+ 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?");
+ }
+ }
+
+ // 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::RegionOutlives(..)
+ | ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::TypeOutlives(..) => {
+ let predicate = self.resolve_vars_if_possible(obligation.predicate);
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0280,
+ "the requirement `{}` is not satisfied",
+ predicate
+ )
+ }
+
+ 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_substs, kind) => {
+ let found_kind = self.closure_kind(closure_substs).unwrap();
+ let closure_span = self.tcx.def_span(closure_def_id);
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ closure_span,
+ E0525,
+ "expected a closure that implements the `{}` trait, \
+ but this closure only implements `{}`",
+ kind,
+ found_kind
+ );
+
+ err.span_label(
+ closure_span,
+ format!("this closure implements `{}`, not `{}`", found_kind, kind),
+ );
+ err.span_label(
+ obligation.cause.span,
+ format!("the requirement to implement `{}` derives from here", kind),
+ );
+
+ // Additional context information explaining why the closure only implements
+ // a particular trait.
+ if let Some(typeck_results) = self.in_progress_typeck_results {
+ let hir_id = self
+ .tcx
+ .hir()
+ .local_def_id_to_hir_id(closure_def_id.expect_local());
+ let typeck_results = typeck_results.borrow();
+ match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
+ (ty::ClosureKind::FnOnce, Some((span, place))) => {
+ err.span_label(
+ *span,
+ format!(
+ "closure is `FnOnce` because it moves the \
+ variable `{}` out of its environment",
+ ty::place_to_string_for_capture(tcx, place)
+ ),
+ );
+ }
+ (ty::ClosureKind::FnMut, Some((span, place))) => {
+ err.span_label(
+ *span,
+ format!(
+ "closure is `FnMut` because it mutates the \
+ variable `{}` here",
+ ty::place_to_string_for_capture(tcx, place)
+ ),
+ );
+ }
+ _ => {}
+ }
+ }
+
+ err.emit();
+ return;
+ }
+
+ ty::PredicateKind::WellFormed(ty) => {
+ if !self.tcx.sess.opts.unstable_opts.chalk {
+ // 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);
+ } else {
+ // 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 `{}` is not well-formed (chalk)", ty),
+ )
+ }
+ }
+
+ ty::PredicateKind::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::TypeWellFormedFromEnv(..) => span_bug!(
+ span,
+ "TypeWellFormedFromEnv predicate should only exist in the environment"
+ ),
+ }
+ }
+
+ OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
+ let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
+ let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
+
+ if expected_trait_ref.self_ty().references_error() {
+ return;
+ }
+
+ let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
+ return;
+ };
+
+ let found_did = match *found_trait_ty.kind() {
+ ty::Closure(did, _)
+ | ty::Foreign(did)
+ | ty::FnDef(did, _)
+ | ty::Generator(did, ..) => Some(did),
+ ty::Adt(def, _) => Some(def.did()),
+ _ => None,
+ };
+
+ let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
+
+ if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
+ // We check closures twice, with obligations flowing in different directions,
+ // but we want to complain about them only once.
+ return;
+ }
+
+ self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
+ let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
+ ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+ _ => vec![ArgKind::empty()],
+ };
+
+ let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
+ let expected = match expected_ty.kind() {
+ ty::Tuple(ref tys) => {
+ tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
+ }
+ _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())],
+ };
+
+ if found.len() == expected.len() {
+ self.report_closure_arg_mismatch(
+ span,
+ found_span,
+ found_trait_ref,
+ expected_trait_ref,
+ )
+ } else {
+ let (closure_span, found) = found_did
+ .and_then(|did| {
+ let node = self.tcx.hir().get_if_local(did)?;
+ let (found_span, found) = self.get_fn_like_arguments(node)?;
+ Some((Some(found_span), found))
+ })
+ .unwrap_or((found_span, found));
+
+ self.report_arg_count_mismatch(
+ span,
+ closure_span,
+ expected,
+ found,
+ found_trait_ty.is_closure(),
+ )
+ }
+ }
+
+ 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) => {
+ if !self.tcx.features().generic_const_exprs {
+ let mut err = self.tcx.sess.struct_span_err(
+ span,
+ "constant expression depends on a generic parameter",
+ );
+ // FIXME(const_generics): we should suggest to the user how they can resolve this
+ // issue. However, this is currently not actually possible
+ // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
+ //
+ // Note that with `feature(generic_const_exprs)` this case should not
+ // be reachable.
+ err.note("this may fail depending on what value the parameter takes");
+ err.emit();
+ return;
+ }
+
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ let mut err =
+ self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+ let const_span = self.tcx.def_span(uv.def.did);
+ match self.tcx.sess.source_map().span_to_snippet(const_span) {
+ Ok(snippet) => err.help(&format!(
+ "try adding a `where` bound using this expression: `where [(); {}]:`",
+ snippet
+ )),
+ _ => err.help("consider adding a `where` bound using this expression"),
+ };
+ err
+ }
+ _ => {
+ span_bug!(
+ span,
+ "unexpected non-ConstEvaluatable predicate, this should not be reachable"
+ )
+ }
+ }
+ }
+
+ // Already reported in the query.
+ SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(_)) => {
+ // FIXME(eddyb) remove this once `ErrorGuaranteed` becomes a proof token.
+ self.tcx.sess.delay_span_bug(span, "`ErrorGuaranteed` without an error");
+ return;
+ }
+ // Already reported.
+ Overflow(OverflowError::Error(_)) => {
+ self.tcx.sess.delay_span_bug(span, "`OverflowError` has been reported");
+ 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();
+ }
+
+ /// 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, 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_decl_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,
+ 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, 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,
+ ) -> 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(_, ref 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 {} that takes {}", kind, expected_str));
+
+ if let Some(found_span) = found_span {
+ err.span_label(found_span, format!("takes {}", found_str));
+
+ // move |_| { ... }
+ // ^^^^^^^^-- def_span
+ //
+ // move |_| { ... }
+ // ^^^^^-- prefix
+ let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
+ // move |_| { ... }
+ // ^^^-- pipe_span
+ let pipe_span =
+ if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
+
+ // Suggest to take and ignore the arguments with expected_args_length `_`s if
+ // found arguments is empty (assume the user just wants to ignore args in this case).
+ // For example, if `expected_args_length` is 2, suggest `|_, _|`.
+ if found_args.is_empty() && is_closure {
+ let underscores = vec!["_"; expected_args.len()].join(", ");
+ err.span_suggestion_verbose(
+ pipe_span,
+ &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>>,
+ constness: ty::BoundConstness,
+ 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,
+ });
+ let substs = self.tcx.mk_substs_trait(ty.skip_binder(), &[var.into()]);
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ ty.rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef::new(trait_def_id, substs),
+ constness,
+ polarity,
+ })
+ .to_predicate(self.tcx),
+ );
+ let mut fulfill_cx = FulfillmentContext::new_in_snapshot();
+ fulfill_cx.register_predicate_obligation(self, obligation);
+ if fulfill_cx.select_all_or_error(self).is_empty() {
+ return Ok((
+ ty::ClosureKind::from_def_id(self.tcx, trait_def_id)
+ .expect("expected to map DefId to ClosureKind"),
+ ty.rebind(self.resolve_vars_if_possible(var)),
+ ));
+ }
+ }
+
+ Err(())
+ })
+ }
+}
+
+trait InferCtxtPrivExt<'hir, '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>,
+ body_id: Option<hir::BodyId>,
+ fallback_has_occurred: bool,
+ );
+
+ fn report_projection_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ error: &MismatchedProjectionTypes<'tcx>,
+ );
+
+ 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: Vec<ImplCandidate<'tcx>>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ body_id: hir::HirId,
+ err: &mut Diagnostic,
+ ) -> bool;
+
+ /// 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>,
+ body_id: Option<hir::BodyId>,
+ );
+
+ fn predicate_can_apply(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ pred: ty::PolyTraitRef<'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: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ );
+
+ fn maybe_suggest_unsized_generics(&self, err: &mut Diagnostic, span: Span, node: Node<'hir>);
+
+ fn maybe_indirection_for_unsized(
+ &self,
+ err: &mut Diagnostic,
+ item: &'hir Item<'hir>,
+ param: &'hir GenericParam<'hir>,
+ ) -> bool;
+
+ fn is_recursive_obligation(
+ &self,
+ obligated_types: &mut Vec<Ty<'tcx>>,
+ cause_code: &ObligationCauseCode<'tcx>,
+ ) -> bool;
+}
+
+impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, '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::Trait(..), ty::PredicateKind::Trait(error)) => {
+ (cond, bound_error.rebind(error))
+ }
+ _ => {
+ // FIXME: make this work in other cases too.
+ return false;
+ }
+ };
+
+ for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
+ let bound_predicate = obligation.predicate.kind();
+ if let ty::PredicateKind::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).is_ok() {
+ debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
+ return true;
+ }
+ }
+ }
+
+ false
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn report_fulfillment_error(
+ &self,
+ error: &FulfillmentError<'tcx>,
+ body_id: Option<hir::BodyId>,
+ fallback_has_occurred: bool,
+ ) {
+ match error.code {
+ FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
+ self.report_selection_error(
+ error.obligation.clone(),
+ &error.root_obligation,
+ selection_error,
+ fallback_has_occurred,
+ );
+ }
+ FulfillmentErrorCode::CodeProjectionError(ref e) => {
+ self.report_projection_error(&error.obligation, e);
+ }
+ FulfillmentErrorCode::CodeAmbiguity => {
+ self.maybe_report_ambiguity(&error.obligation, body_id);
+ }
+ FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
+ self.report_mismatched_types(
+ &error.obligation.cause,
+ expected_found.expected,
+ expected_found.found,
+ err.clone(),
+ )
+ .emit();
+ }
+ FulfillmentErrorCode::CodeConstEquateError(ref expected_found, ref err) => {
+ self.report_mismatched_consts(
+ &error.obligation.cause,
+ expected_found.expected,
+ expected_found.found,
+ err.clone(),
+ )
+ .emit();
+ }
+ }
+ }
+
+ #[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 err_buf;
+ let mut err = &error.err;
+ let mut values = None;
+
+ // try to find the mismatched types to report the error with.
+ //
+ // this can fail if the problem was higher-ranked, in which
+ // cause I have no idea for a good error message.
+ let bound_predicate = predicate.kind();
+ if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() {
+ let mut selcx = SelectionContext::new(self);
+ let data = self.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ infer::LateBoundRegionConversionTime::HigherRankedType,
+ bound_predicate.rebind(data),
+ );
+ let mut obligations = vec![];
+ let normalized_ty = super::normalize_projection_type(
+ &mut selcx,
+ obligation.param_env,
+ data.projection_ty,
+ obligation.cause.clone(),
+ 0,
+ &mut obligations,
+ );
+
+ debug!(?obligation.cause, ?obligation.param_env);
+
+ debug!(?normalized_ty, data.ty = ?data.term);
+
+ let is_normalized_ty_expected = !matches!(
+ obligation.cause.code().peel_derives(),
+ ObligationCauseCode::ItemObligation(_)
+ | ObligationCauseCode::BindingObligation(_, _)
+ | ObligationCauseCode::ObjectCastObligation(..)
+ | ObligationCauseCode::OpaqueType
+ );
+ if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
+ is_normalized_ty_expected,
+ normalized_ty,
+ data.term,
+ ) {
+ values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
+ is_normalized_ty_expected,
+ normalized_ty,
+ data.term,
+ )));
+ err_buf = error;
+ err = &err_buf;
+ }
+ }
+
+ let mut diag = struct_span_err!(
+ self.tcx.sess,
+ obligation.cause.span,
+ E0271,
+ "type mismatch resolving `{}`",
+ predicate
+ );
+ let secondary_span = match predicate.kind().skip_binder() {
+ ty::PredicateKind::Projection(proj) => self
+ .tcx
+ .opt_associated_item(proj.projection_ty.item_def_id)
+ .and_then(|trait_assoc_item| {
+ self.tcx
+ .trait_of_item(proj.projection_ty.item_def_id)
+ .map(|id| (trait_assoc_item, id))
+ })
+ .and_then(|(trait_assoc_item, id)| {
+ let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
+ self.tcx.find_map_relevant_impl(id, proj.projection_ty.self_ty(), |did| {
+ self.tcx
+ .associated_items(did)
+ .in_definition_order()
+ .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
+ })
+ })
+ .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
+ Some(
+ hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Type(_, Some(ty)),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::TyAlias(ty),
+ ..
+ }),
+ ) => Some((ty.span, format!("type mismatch resolving `{}`", predicate))),
+ _ => None,
+ }),
+ _ => None,
+ };
+ self.note_type_err(
+ &mut diag,
+ &obligation.cause,
+ secondary_span,
+ values,
+ err,
+ true,
+ false,
+ );
+ self.note_obligation_cause(&mut diag, obligation);
+ diag.emit();
+ });
+ }
+
+ 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 tcx.is_diagnostic_item(sym::String, def.did()) => 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::Projection(..) => Some(12),
+ ty::Opaque(..) => Some(13),
+ ty::Never => Some(14),
+ ty::Adt(..) => Some(15),
+ ty::Generator(..) => Some(16),
+ ty::Foreign(..) => Some(17),
+ ty::GeneratorWitness(..) => Some(18),
+ ty::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>> {
+ self.tcx
+ .all_impls(trait_pred.def_id())
+ .filter_map(|def_id| {
+ if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative
+ || !trait_pred
+ .skip_binder()
+ .is_constness_satisfied_by(self.tcx.constness(def_id))
+ {
+ return None;
+ }
+
+ let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+
+ self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false)
+ .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
+ })
+ .collect()
+ }
+
+ fn report_similar_impl_candidates(
+ &self,
+ impl_candidates: Vec<ImplCandidate<'tcx>>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ body_id: hir::HirId,
+ err: &mut Diagnostic,
+ ) -> bool {
+ let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
+ candidates.sort();
+ candidates.dedup();
+ let len = candidates.len();
+ if candidates.len() == 0 {
+ return false;
+ }
+ if candidates.len() == 1 {
+ err.highlighted_help(vec![
+ (
+ format!("the trait `{}` ", candidates[0].print_only_trait_path()),
+ Style::NoStyle,
+ ),
+ ("is".to_string(), Style::Highlight),
+ (" implemented for `".to_string(), Style::NoStyle),
+ (candidates[0].self_ty().to_string(), Style::Highlight),
+ ("`".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();
+
+ let mut candidates: Vec<String> = candidates
+ .into_iter()
+ .map(|c| {
+ if traits.len() == 1 {
+ format!("\n {}", c.self_ty())
+ } else {
+ format!("\n {}", c)
+ }
+ })
+ .collect();
+
+ candidates.sort();
+ candidates.dedup();
+ 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 len > 9 { format!("\nand {} others", 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().items().contains(&Some(def_id))
+ || self.tcx.get_diagnostic_name(def_id).is_some()
+ {
+ // Mentioning implementers of `Copy`, `Debug` and friends is not useful.
+ return false;
+ }
+ let normalized_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_builtin_derive(def_id)
+ })
+ .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
+ .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_id.owner.to_def_id(), self.tcx)
+ } else {
+ true
+ }
+ })
+ .collect();
+ return report(normalized_impl_candidates, err);
+ }
+
+ let normalize = |candidate| {
+ self.tcx.infer_ctxt().enter(|ref infcx| {
+ let normalized = infcx
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .normalize(candidate)
+ .ok();
+ match normalized {
+ Some(normalized) => normalized.value,
+ None => candidate,
+ }
+ })
+ };
+
+ // 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 normalized_impl_candidates_and_similarities = impl_candidates
+ .into_iter()
+ .map(|ImplCandidate { trait_ref, similarity }| {
+ let normalized = normalize(trait_ref);
+ (similarity, normalized)
+ })
+ .collect::<Vec<_>>();
+ normalized_impl_candidates_and_similarities.sort();
+ normalized_impl_candidates_and_similarities.dedup();
+
+ let normalized_impl_candidates = normalized_impl_candidates_and_similarities
+ .into_iter()
+ .map(|(_, normalized)| normalized)
+ .collect::<Vec<_>>();
+
+ report(normalized_impl_candidates, err)
+ }
+
+ /// 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_impl = |trait_def_id| {
+ self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some)
+ };
+ 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 {
+ if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
+ let impl_span = self.tcx.def_span(impl_def_id);
+ err.span_help(impl_span, "trait impl with same name found");
+ let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
+ let crate_msg = format!(
+ "perhaps two different versions of crate `{}` are being used?",
+ trait_crate
+ );
+ err.note(&crate_msg);
+ suggested = true;
+ }
+ }
+ 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_ref(|(tr, new_self_ty)| ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
+ ..tr.trait_ref
+ },
+ ..*tr
+ });
+
+ Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx))
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn maybe_report_ambiguity(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ body_id: Option<hir::BodyId>,
+ ) {
+ // 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 = tracing::field::debug(&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::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 !self.is_tainted_by_errors() {
+ self.emit_inference_failure_err(
+ 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.substs.iter().find(|s| s.has_infer_types_or_consts());
+
+ let mut err = if let Some(subst) = subst {
+ self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
+ } else {
+ struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0283,
+ "type annotations needed: cannot satisfy `{}`",
+ predicate,
+ )
+ };
+
+ let obligation = Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ trait_ref.to_poly_trait_predicate(),
+ );
+ let mut selcx = SelectionContext::with_query_mode(
+ &self,
+ crate::traits::TraitQueryMode::Standard,
+ );
+ match selcx.select_from_obligation(&obligation) {
+ Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
+ self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ }
+ _ => {
+ if self.is_tainted_by_errors() {
+ err.cancel();
+ return;
+ }
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ }
+
+ if let ObligationCauseCode::ItemObligation(def_id) = *obligation.cause.code() {
+ self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+ } else if let (
+ Ok(ref snippet),
+ &ObligationCauseCode::BindingObligation(def_id, _),
+ ) =
+ (self.tcx.sess.source_map().span_to_snippet(span), obligation.cause.code())
+ {
+ let generics = self.tcx.generics_of(def_id);
+ if generics.params.iter().any(|p| p.name != kw::SelfUpper)
+ && !snippet.ends_with('>')
+ && !generics.has_impl_trait()
+ && !self.tcx.fn_trait_kind_from_lang_item(def_id).is_some()
+ {
+ // FIXME: To avoid spurious suggestions in functions where type arguments
+ // where already supplied, we check the snippet to make sure it doesn't
+ // end with a turbofish. Ideally we would have access to a `PathSegment`
+ // instead. Otherwise we would produce the following output:
+ //
+ // error[E0283]: type annotations needed
+ // --> $DIR/issue-54954.rs:3:24
+ // |
+ // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+ // | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // | |
+ // | cannot infer type
+ // | help: consider specifying the type argument
+ // | in the function call:
+ // | `Tt::const_val::<[i8; 123]>::<T>`
+ // ...
+ // LL | const fn const_val<T: Sized>() -> usize {
+ // | - required by this bound in `Tt::const_val`
+ // |
+ // = note: cannot satisfy `_: Tt`
+
+ // Clear any more general suggestions in favor of our specific one
+ err.clear_suggestions();
+
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ &format!(
+ "consider specifying the type argument{} in the function call",
+ pluralize!(generics.params.len()),
+ ),
+ format!(
+ "::<{}>",
+ generics
+ .params
+ .iter()
+ .map(|p| p.name.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")
+ ),
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+
+ if let (Some(body_id), Some(ty::subst::GenericArgKind::Type(_))) =
+ (body_id, subst.map(|subst| subst.unpack()))
+ {
+ struct FindExprBySpan<'hir> {
+ span: Span,
+ result: Option<&'hir hir::Expr<'hir>>,
+ }
+
+ impl<'v> hir::intravisit::Visitor<'v> for FindExprBySpan<'v> {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ if self.span == ex.span {
+ self.result = Some(ex);
+ } else {
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+ }
+
+ let mut expr_finder = FindExprBySpan { span, result: None };
+
+ 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: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)),
+ ..
+ },
+ hir::PathSegment {
+ ident: assoc_item_name,
+ res: Some(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)
+ && !self.is_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!("`{}::{}` defined here", trait_name, assoc_item_name));
+ }
+
+ 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_ty, _)) = trait_impls.non_blanket_impls().iter().next()
+ && let Some(impl_def_id) = impl_ty.def() {
+ let message = if trait_impls.non_blanket_impls().len() == 1 {
+ "use the fully-qualified path to the only available implementation".to_string()
+ } else {
+ format!(
+ "use a fully-qualified path to a specific available implementation ({} found)",
+ trait_impls.non_blanket_impls().len()
+ )
+ };
+
+ err.multipart_suggestion(
+ message,
+ vec![
+ (trait_path_segment.ident.span.shrink_to_lo(), format!("<{} as ", self.tcx.def_path(impl_def_id).to_string_no_crate_verbose())),
+ (trait_path_segment.ident.span.shrink_to_hi(), format!(">"))
+ ],
+ Applicability::MaybeIncorrect
+ );
+ }
+ }
+ };
+
+ err
+ }
+
+ ty::PredicateKind::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.is_tainted_by_errors()
+ {
+ return;
+ }
+
+ self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false)
+ }
+
+ ty::PredicateKind::Subtype(data) => {
+ if data.references_error()
+ || self.tcx.sess.has_errors().is_some()
+ || self.is_tainted_by_errors()
+ {
+ // 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(body_id, span, a.into(), ErrorCode::E0282, true)
+ }
+ ty::PredicateKind::Projection(data) => {
+ if predicate.references_error() || self.is_tainted_by_errors() {
+ return;
+ }
+ let subst = data
+ .projection_ty
+ .substs
+ .iter()
+ .chain(Some(data.term.into_arg()))
+ .find(|g| g.has_infer_types_or_consts());
+ if let Some(subst) = subst {
+ let mut err = self.emit_inference_failure_err(
+ 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::ConstEvaluatable(data) => {
+ if predicate.references_error() || self.is_tainted_by_errors() {
+ return;
+ }
+ let subst = data.substs.iter().find(|g| g.has_infer_types_or_consts());
+ if let Some(subst) = subst {
+ let err = self.emit_inference_failure_err(
+ 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.is_tainted_by_errors() {
+ 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,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ ) {
+ let mut spans = vec![];
+ let mut crates = vec![];
+ let mut post = vec![];
+ for def_id in impls {
+ match self.tcx.span_of_impl(*def_id) {
+ Ok(span) => spans.push(span),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
+ post.push(header);
+ }
+ }
+ }
+ }
+ let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
+ crate_names.sort();
+ crate_names.dedup();
+ post.sort();
+ post.dedup();
+
+ if self.is_tainted_by_errors()
+ && (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 post = if post.len() > 4 {
+ format!(
+ ":\n{}\nand {} more",
+ post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
+ post.len() - 4,
+ )
+ } else 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::PolyTraitRef<'tcx>,
+ ) -> bool {
+ struct ParamToVarFolder<'a, 'tcx> {
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
+ }
+
+ impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
+ let infcx = self.infcx;
+ *self.var_map.entry(ty).or_insert_with(|| {
+ infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
+ span: DUMMY_SP,
+ })
+ })
+ } else {
+ ty.super_fold_with(self)
+ }
+ }
+ }
+
+ self.probe(|_| {
+ let mut selcx = SelectionContext::new(self);
+
+ let cleaned_pred =
+ pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() });
+
+ let cleaned_pred = super::project::normalize(
+ &mut selcx,
+ param_env,
+ ObligationCause::dummy(),
+ cleaned_pred,
+ )
+ .value;
+
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ param_env,
+ cleaned_pred.without_const().to_predicate(selcx.tcx()),
+ );
+
+ 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(
+ 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::Trait(pred),
+ &ObligationCauseCode::BindingObligation(item_def_id, span),
+ ) = (
+ obligation.predicate.kind().skip_binder(),
+ 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<'hir>(
+ &self,
+ err: &mut Diagnostic,
+ span: Span,
+ node: Node<'hir>,
+ ) {
+ 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;
+ };
+ let param_def_id = self.tcx.hir().local_def_id(param.hir_id);
+ // 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!("{} ?Sized", separator),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ fn maybe_indirection_for_unsized<'hir>(
+ &self,
+ err: &mut Diagnostic,
+ item: &'hir Item<'hir>,
+ param: &'hir GenericParam<'hir>,
+ ) -> 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, substs) = self_ty.kind()
+ && let [arg] = &substs[..]
+ && let ty::subst::GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Adt(inner_def, _) = ty.kind()
+ && inner_def == def
+ {
+ return true;
+ }
+ }
+ false
+ }
+}
+
+/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
+/// `param: ?Sized` would be a valid constraint.
+struct FindTypeParam {
+ param: rustc_span::Symbol,
+ invalid_spans: Vec<Span>,
+ nested: bool,
+}
+
+impl<'v> Visitor<'v> for FindTypeParam {
+ fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+ // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+ }
+
+ fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+ // We collect the spans of all uses of the "bare" type param, like in `field: T` or
+ // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
+ // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+ // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
+ // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
+ // in that case should make what happened clear enough.
+ match ty.kind {
+ hir::TyKind::Ptr(_) | hir::TyKind::Rptr(..) | hir::TyKind::TraitObject(..) => {}
+ hir::TyKind::Path(hir::QPath::Resolved(None, path))
+ if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+ {
+ if !self.nested {
+ debug!(?ty, "FindTypeParam::visit_ty");
+ self.invalid_spans.push(ty.span);
+ }
+ }
+ hir::TyKind::Path(_) => {
+ let prev = self.nested;
+ self.nested = true;
+ hir::intravisit::walk_ty(self, ty);
+ self.nested = prev;
+ }
+ _ => {
+ hir::intravisit::walk_ty(self, ty);
+ }
+ }
+ }
+}
+
+pub fn recursive_type_with_infinite_size_error<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ type_def_id: DefId,
+ spans: Vec<(Span, Option<hir::HirId>)>,
+) {
+ assert!(type_def_id.is_local());
+ let span = tcx.def_span(type_def_id);
+ let path = tcx.def_path_str(type_def_id);
+ let mut err =
+ struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
+ err.span_label(span, "recursive type has infinite size");
+ for &(span, _) in &spans {
+ err.span_label(span, "recursive without indirection");
+ }
+ let msg = format!(
+ "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
+ path,
+ );
+ if spans.len() <= 4 {
+ // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
+ err.multipart_suggestion(
+ &msg,
+ spans
+ .into_iter()
+ .flat_map(|(span, field_id)| {
+ if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
+ // If we match an `Option` and can grab the span of the Option's generic, then
+ // suggest boxing the generic arg for a non-null niche optimization.
+ vec![
+ (generic_span.shrink_to_lo(), "Box<".to_string()),
+ (generic_span.shrink_to_hi(), ">".to_string()),
+ ]
+ } else {
+ vec![
+ (span.shrink_to_lo(), "Box<".to_string()),
+ (span.shrink_to_hi(), ">".to_string()),
+ ]
+ }
+ })
+ .collect(),
+ Applicability::HasPlaceholders,
+ );
+ } else {
+ err.help(&msg);
+ }
+ err.emit();
+}
+
+/// Extract the span for the generic type `T` of `Option<T>` in a field definition
+fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
+ let node = tcx.hir().find(field_id?);
+
+ // Expect a field from our field_id
+ let Some(hir::Node::Field(field_def)) = node
+ else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };
+
+ // Match a type that is a simple QPath with no Self
+ let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
+ else { return None };
+
+ // Check if the path we're checking resolves to Option
+ let hir::def::Res::Def(_, did) = path.res
+ else { return None };
+
+ // Bail if this path doesn't describe `::core::option::Option`
+ if !tcx.is_diagnostic_item(sym::Option, did) {
+ return None;
+ }
+
+ // Match a single generic arg in the 0th path segment
+ let generic_arg = path.segments.last()?.args?.args.get(0)?;
+
+ // Take the span out of the type, if it's a type
+ if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
+}
+
+/// Summarizes information
+#[derive(Clone)]
+pub enum ArgKind {
+ /// An argument of non-tuple type. Parameters are (name, ty)
+ Arg(String, String),
+
+ /// An argument of tuple type. For a "found" argument, the span is
+ /// the location in the source of the pattern. For an "expected"
+ /// argument, it will be None. The vector is a list of (name, ty)
+ /// strings for the components of the tuple.
+ Tuple(Option<Span>, Vec<(String, String)>),
+}
+
+impl ArgKind {
+ fn empty() -> ArgKind {
+ ArgKind::Arg("_".to_owned(), "_".to_owned())
+ }
+
+ /// Creates an `ArgKind` from the expected type of an
+ /// argument. It has no name (`_`) and an optional source span.
+ pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
+ match t.kind() {
+ ty::Tuple(tys) => ArgKind::Tuple(
+ span,
+ tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(),
+ ),
+ _ => ArgKind::Arg("_".to_owned(), t.to_string()),
+ }
+ }
+}
+
+struct HasNumericInferVisitor;
+
+impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+}
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
new file mode 100644
index 000000000..e6907637c
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -0,0 +1,272 @@
+use super::{
+ ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
+};
+use crate::infer::InferCtxt;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::{self, GenericParamDefKind};
+use rustc_span::symbol::sym;
+use std::iter;
+
+use super::InferCtxtPrivExt;
+
+pub trait InferCtxtExt<'tcx> {
+ /*private*/
+ fn impl_similar_to(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Option<(DefId, SubstsRef<'tcx>)>;
+
+ /*private*/
+ fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
+
+ fn on_unimplemented_note(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> OnUnimplementedNote;
+}
+
+impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+ fn impl_similar_to(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Option<(DefId, SubstsRef<'tcx>)> {
+ let tcx = self.tcx;
+ let param_env = obligation.param_env;
+ let trait_ref = tcx.erase_late_bound_regions(trait_ref);
+ let trait_self_ty = trait_ref.self_ty();
+
+ let mut self_match_impls = vec![];
+ let mut fuzzy_match_impls = vec![];
+
+ self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| {
+ let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id);
+ let impl_trait_ref = tcx.bound_impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs);
+
+ let impl_self_ty = impl_trait_ref.self_ty();
+
+ if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
+ self_match_impls.push((def_id, impl_substs));
+
+ if iter::zip(
+ trait_ref.substs.types().skip(1),
+ impl_trait_ref.substs.types().skip(1),
+ )
+ .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
+ {
+ fuzzy_match_impls.push((def_id, impl_substs));
+ }
+ }
+ });
+
+ let impl_def_id_and_substs = if self_match_impls.len() == 1 {
+ self_match_impls[0]
+ } else if fuzzy_match_impls.len() == 1 {
+ fuzzy_match_impls[0]
+ } else {
+ return None;
+ };
+
+ tcx.has_attr(impl_def_id_and_substs.0, sym::rustc_on_unimplemented)
+ .then_some(impl_def_id_and_substs)
+ }
+
+ /// Used to set on_unimplemented's `ItemContext`
+ /// to be the enclosing (async) block/function/closure
+ fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
+ let hir = self.tcx.hir();
+ 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(|| {
+ Some(match sig.header {
+ hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async function",
+ _ => "a function",
+ })
+ })
+ }
+ 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")),
+ hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(sig, body_id),
+ ..
+ }) => self.describe_generator(*body_id).or_else(|| {
+ Some(match sig.header {
+ hir::FnHeader { asyncness: hir::IsAsync::Async, .. } => "an async method",
+ _ => "a method",
+ })
+ }),
+ hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }),
+ ..
+ }) => self.describe_generator(*body).or_else(|| {
+ Some(if movability.is_some() { "an async closure" } else { "a closure" })
+ }),
+ hir::Node::Expr(hir::Expr { .. }) => {
+ let parent_hid = hir.get_parent_node(hir_id);
+ if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None }
+ }
+ _ => None,
+ }
+ }
+
+ fn on_unimplemented_note(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> OnUnimplementedNote {
+ let (def_id, substs) = self
+ .impl_similar_to(trait_ref, obligation)
+ .unwrap_or_else(|| (trait_ref.def_id(), trait_ref.skip_binder().substs));
+ let trait_ref = trait_ref.skip_binder();
+
+ let mut flags = vec![(
+ sym::ItemContext,
+ self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
+ )];
+
+ match obligation.cause.code() {
+ ObligationCauseCode::BuiltinDerivedObligation(..)
+ | ObligationCauseCode::ImplDerivedObligation(..)
+ | ObligationCauseCode::DerivedObligation(..) => {}
+ _ => {
+ // this is a "direct", user-specified, rather than derived,
+ // obligation.
+ flags.push((sym::direct, None));
+ }
+ }
+
+ if let ObligationCauseCode::ItemObligation(item)
+ | ObligationCauseCode::BindingObligation(item, _) = *obligation.cause.code()
+ {
+ // FIXME: maybe also have some way of handling methods
+ // from other traits? That would require name resolution,
+ // which we might want to be some sort of hygienic.
+ //
+ // Currently I'm leaving it for what I need for `try`.
+ if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
+ let method = self.tcx.item_name(item);
+ flags.push((sym::from_method, None));
+ flags.push((sym::from_method, Some(method.to_string())));
+ }
+ }
+
+ if let Some(k) = obligation.cause.span.desugaring_kind() {
+ flags.push((sym::from_desugaring, None));
+ flags.push((sym::from_desugaring, Some(format!("{:?}", k))));
+ }
+
+ // Add all types without trimmed paths.
+ ty::print::with_no_trimmed_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`,
+ // but the parser won't allow you to use it
+ flags.push((sym::_Self, Some(self_ty.to_string())));
+ if let Some(def) = self_ty.ty_adt_def() {
+ // We also want to be able to select self's original
+ // signature with no type arguments resolved
+ flags.push((sym::_Self, Some(self.tcx.type_of(def.did()).to_string())));
+ }
+
+ for param in generics.params.iter() {
+ let value = match param.kind {
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+ substs[param.index as usize].to_string()
+ }
+ GenericParamDefKind::Lifetime => continue,
+ };
+ let name = param.name;
+ flags.push((name, Some(value)));
+
+ if let GenericParamDefKind::Type { .. } = param.kind {
+ let param_ty = substs[param.index as usize].expect_ty();
+ if let Some(def) = param_ty.ty_adt_def() {
+ // We also want to be able to select the parameter's
+ // original signature with no type arguments resolved
+ flags.push((name, Some(self.tcx.type_of(def.did()).to_string())));
+ }
+ }
+ }
+
+ if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
+ flags.push((sym::crate_local, None));
+ }
+
+ // Allow targeting all integers using `{integral}`, even if the exact type was resolved
+ if self_ty.is_integral() {
+ flags.push((sym::_Self, Some("{integral}".to_owned())));
+ }
+
+ if self_ty.is_array_slice() {
+ flags.push((sym::_Self, Some("&[]".to_owned())));
+ }
+
+ if self_ty.is_fn() {
+ let fn_sig = self_ty.fn_sig(self.tcx);
+ let shortname = match fn_sig.unsafety() {
+ hir::Unsafety::Normal => "fn",
+ hir::Unsafety::Unsafe => "unsafe fn",
+ };
+ flags.push((sym::_Self, Some(shortname.to_owned())));
+ }
+
+ // Slices give us `[]`, `[{ty}]`
+ if let ty::Slice(aty) = self_ty.kind() {
+ flags.push((sym::_Self, Some("[]".to_string())));
+ if let Some(def) = aty.ty_adt_def() {
+ // We also want to be able to select the slice's type's original
+ // signature with no type arguments resolved
+ flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did())))));
+ }
+ if aty.is_integral() {
+ flags.push((sym::_Self, Some("[{integral}]".to_string())));
+ }
+ }
+
+ // Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
+ if let ty::Array(aty, len) = self_ty.kind() {
+ flags.push((sym::_Self, Some("[]".to_string())));
+ let len = len.kind().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+ flags.push((sym::_Self, Some(format!("[{}; _]", aty))));
+ if let Some(n) = len {
+ flags.push((sym::_Self, Some(format!("[{}; {}]", aty, n))));
+ }
+ if let Some(def) = aty.ty_adt_def() {
+ // We also want to be able to select the array's type's original
+ // signature with no type arguments resolved
+ let def_ty = self.tcx.type_of(def.did());
+ flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
+ if let Some(n) = len {
+ flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
+ }
+ }
+ if aty.is_integral() {
+ flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
+ if let Some(n) = len {
+ flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
+ }
+ }
+ }
+ if let ty::Dynamic(traits, _) = self_ty.kind() {
+ for t in traits.iter() {
+ if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
+ flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
+ }
+ }
+ }
+ });
+
+ if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
+ command.evaluate(self.tcx, trait_ref, &flags)
+ } else {
+ OnUnimplementedNote::default()
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
new file mode 100644
index 000000000..219413121
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -0,0 +1,3119 @@
+use super::{
+ EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
+ SelectionContext,
+};
+
+use crate::autoderef::Autoderef;
+use crate::infer::InferCtxt;
+use crate::traits::normalize_to;
+
+use hir::HirId;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_errors::{
+ error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+ ErrorGuaranteed, MultiSpan, Style,
+};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::hir::map;
+use rustc_middle::ty::{
+ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
+ ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitable,
+};
+use rustc_middle::ty::{TypeAndMut, TypeckResults};
+use rustc_session::Limit;
+use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span, DUMMY_SP};
+use rustc_target::spec::abi;
+use std::fmt;
+
+use super::InferCtxtPrivExt;
+use crate::infer::InferCtxtExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+
+#[derive(Debug)]
+pub enum GeneratorInteriorOrUpvar {
+ // span of interior type
+ Interior(Span),
+ // span of upvar
+ Upvar(Span),
+}
+
+// This type provides a uniform interface to retrieve data on generators, whether it originated from
+// the local crate being compiled or from a foreign crate.
+#[derive(Debug)]
+pub enum GeneratorData<'tcx, 'a> {
+ Local(&'a TypeckResults<'tcx>),
+ Foreign(&'tcx GeneratorDiagnosticData<'tcx>),
+}
+
+impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
+ // Try to get information about variables captured by the generator 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<'a, 'tcx>,
+ generator_did: DefId,
+ ty_matches: F,
+ ) -> Option<GeneratorInteriorOrUpvar>
+ where
+ F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+ {
+ match self {
+ GeneratorData::Local(typeck_results) => {
+ infer_context.tcx.upvars_mentioned(generator_did).and_then(|upvars| {
+ upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = typeck_results.node_type(*upvar_id);
+ let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty);
+ if ty_matches(ty::Binder::dummy(upvar_ty)) {
+ Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ } else {
+ None
+ }
+ })
+ })
+ }
+ GeneratorData::Foreign(_) => None,
+ }
+ }
+
+ // Try to get the span of a type being awaited on that matches the type we are looking with the
+ // `ty_matches` function. We uses it to find awaited type which causes a failure to meet an
+ // obligation
+ fn get_from_await_ty<F>(
+ &self,
+ visitor: AwaitsVisitor,
+ hir: map::Map<'tcx>,
+ ty_matches: F,
+ ) -> Option<Span>
+ where
+ F: Fn(ty::Binder<'tcx, Ty<'tcx>>) -> bool,
+ {
+ match self {
+ GeneratorData::Local(typeck_results) => visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+ })
+ .map(|expr| expr.span),
+ GeneratorData::Foreign(generator_diagnostic_data) => visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(
+ generator_diagnostic_data
+ .adjustments
+ .get(&await_expr.hir_id.local_id)
+ .map_or::<&[ty::adjustment::Adjustment<'tcx>], _>(&[], |a| &a[..])
+ .last()
+ .map_or_else::<Ty<'tcx>, _, _>(
+ || {
+ generator_diagnostic_data
+ .nodes_types
+ .get(&await_expr.hir_id.local_id)
+ .cloned()
+ .unwrap_or_else(|| {
+ bug!(
+ "node_type: no type for node `{}`",
+ ty::tls::with(|tcx| tcx
+ .hir()
+ .node_to_string(await_expr.hir_id))
+ )
+ })
+ },
+ |adj| adj.target,
+ ),
+ ))
+ })
+ .map(|expr| expr.span),
+ }
+ }
+
+ /// Get the type, expression, span and optional scope span of all types
+ /// that are live across the yield of this generator
+ fn get_generator_interior_types(
+ &self,
+ ) -> ty::Binder<'tcx, &[GeneratorInteriorTypeCause<'tcx>]> {
+ match self {
+ GeneratorData::Local(typeck_result) => {
+ typeck_result.generator_interior_types.as_deref()
+ }
+ GeneratorData::Foreign(generator_diagnostic_data) => {
+ generator_diagnostic_data.generator_interior_types.as_deref()
+ }
+ }
+ }
+
+ // Used to get the source of the data, note we don't have as much information for generators
+ // originated from foreign crates
+ fn is_foreign(&self) -> bool {
+ match self {
+ GeneratorData::Local(_) => false,
+ GeneratorData::Foreign(_) => true,
+ }
+ }
+}
+
+// This trait is public to expose the diagnostics methods to clippy.
+pub trait InferCtxtExt<'tcx> {
+ fn suggest_restricting_param_bound(
+ &self,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+ body_id: hir::HirId,
+ );
+
+ fn suggest_dereferences(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
+ fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol>;
+
+ fn suggest_fn_call(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
+ fn suggest_add_reference_to_arg(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ has_custom_message: bool,
+ ) -> bool;
+
+ fn suggest_borrowing_for_object_cast(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ self_ty: Ty<'tcx>,
+ object_ty: Ty<'tcx>,
+ );
+
+ fn suggest_remove_reference(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
+ fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic);
+
+ fn suggest_change_mut(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ );
+
+ fn suggest_semicolon_removal(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
+ fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
+
+ fn suggest_impl_trait(
+ &self,
+ err: &mut Diagnostic,
+ span: Span,
+ obligation: &PredicateObligation<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool;
+
+ fn point_at_returns_when_relevant(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ );
+
+ fn report_closure_arg_mismatch(
+ &self,
+ span: Span,
+ found_span: Option<Span>,
+ found: ty::PolyTraitRef<'tcx>,
+ expected: ty::PolyTraitRef<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ fn suggest_fully_qualified_path(
+ &self,
+ err: &mut Diagnostic,
+ item_def_id: DefId,
+ span: Span,
+ trait_ref: DefId,
+ );
+
+ fn maybe_note_obligation_cause_for_async_await(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> bool;
+
+ fn note_obligation_cause_for_async_await(
+ &self,
+ err: &mut Diagnostic,
+ interior_or_upvar_span: GeneratorInteriorOrUpvar,
+ interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
+ is_async: bool,
+ outer_generator: Option<DefId>,
+ trait_pred: ty::TraitPredicate<'tcx>,
+ target_ty: Ty<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
+ obligation: &PredicateObligation<'tcx>,
+ next_code: Option<&ObligationCauseCode<'tcx>>,
+ );
+
+ fn note_obligation_cause_code<T>(
+ &self,
+ err: &mut Diagnostic,
+ predicate: &T,
+ param_env: ty::ParamEnv<'tcx>,
+ cause_code: &ObligationCauseCode<'tcx>,
+ obligated_types: &mut Vec<Ty<'tcx>>,
+ seen_requirements: &mut FxHashSet<DefId>,
+ ) where
+ T: fmt::Display;
+
+ fn suggest_new_overflow_limit(&self, err: &mut Diagnostic);
+
+ /// Suggest to await before try: future? => future.await?
+ fn suggest_await_before_try(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ span: Span,
+ );
+
+ fn suggest_floating_point_literal(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_ref: &ty::PolyTraitRef<'tcx>,
+ );
+
+ fn suggest_derive(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ );
+
+ fn suggest_dereferencing_index(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ );
+}
+
+fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
+ (
+ generics.tail_span_for_predicate_suggestion(),
+ format!("{} {}", generics.add_where_or_trailing_comma(), pred),
+ )
+}
+
+/// 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>(
+ tcx: TyCtxt<'tcx>,
+ hir_id: HirId,
+ hir_generics: &hir::Generics<'tcx>,
+ msg: &str,
+ err: &mut Diagnostic,
+ fn_sig: Option<&hir::FnSig<'_>>,
+ projection: Option<&ty::ProjectionTy<'_>>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ // When we are dealing with a trait, `super_traits` will be `Some`:
+ // Given `trait T: A + B + C {}`
+ // - ^^^^^^^^^ GenericBounds
+ // |
+ // &Ident
+ super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
+) {
+ if hir_generics.where_clause_span.from_expansion()
+ || hir_generics.where_clause_span.desugaring_kind().is_some()
+ {
+ return;
+ }
+ let Some(item_id) = hir_id.as_owner() else { return; };
+ let generics = tcx.generics_of(item_id);
+ // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`...
+ if let Some((param, bound_str, fn_sig)) =
+ fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() {
+ // Shenanigans to get the `Trait` from the `impl Trait`.
+ ty::Param(param) => {
+ let param_def = generics.type_param(param, tcx);
+ if param_def.kind.is_synthetic() {
+ let bound_str =
+ param_def.name.as_str().strip_prefix("impl ")?.trim_start().to_string();
+ return Some((param_def, bound_str, sig));
+ }
+ None
+ }
+ _ => None,
+ })
+ {
+ let type_param_name = hir_generics.params.next_type_param_name(Some(&bound_str));
+ let trait_pred = trait_pred.fold_with(&mut ReplaceImplTraitFolder {
+ tcx,
+ param,
+ replace_ty: ty::ParamTy::new(generics.count() as u32, Symbol::intern(&type_param_name))
+ .to_ty(tcx),
+ });
+ if !trait_pred.is_suggestable(tcx, false) {
+ return;
+ }
+ // We know we have an `impl Trait` that doesn't satisfy a required projection.
+
+ // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments'
+ // types. There should be at least one, but there might be *more* than one. In that
+ // case we could just ignore it and try to identify which one needs the restriction,
+ // but instead we choose to suggest replacing all instances of `impl Trait` with `T`
+ // where `T: Trait`.
+ let mut ty_spans = vec![];
+ for input in fn_sig.decl.inputs {
+ ReplaceImplTraitVisitor { ty_spans: &mut ty_spans, param_did: param.def_id }
+ .visit_ty(input);
+ }
+ // The type param `T: Trait` we will suggest to introduce.
+ let type_param = format!("{}: {}", type_param_name, bound_str);
+
+ let mut sugg = vec![
+ if let Some(span) = hir_generics.span_for_param_suggestion() {
+ (span, format!(", {}", type_param))
+ } else {
+ (hir_generics.span, format!("<{}>", type_param))
+ },
+ // `fn foo(t: impl Trait)`
+ // ^ suggest `where <T as Trait>::A: Bound`
+ predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string()),
+ ];
+ sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
+
+ // Suggest `fn foo<T: Trait>(t: T) where <T as Trait>::A: Bound`.
+ // FIXME: once `#![feature(associated_type_bounds)]` is stabilized, we should suggest
+ // `fn foo(t: impl Trait<A: Bound>)` instead.
+ err.multipart_suggestion(
+ "introduce a type parameter with a trait bound instead of using `impl Trait`",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ if !trait_pred.is_suggestable(tcx, false) {
+ return;
+ }
+ // Trivial case: `T` needs an extra bound: `T: Bound`.
+ let (sp, suggestion) = match (
+ hir_generics
+ .params
+ .iter()
+ .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
+ super_traits,
+ ) {
+ (_, None) => {
+ predicate_constraint(hir_generics, trait_pred.to_predicate(tcx).to_string())
+ }
+ (None, Some((ident, []))) => (
+ ident.span.shrink_to_hi(),
+ format!(": {}", trait_pred.print_modifiers_and_trait_path()),
+ ),
+ (_, Some((_, [.., bounds]))) => (
+ bounds.span().shrink_to_hi(),
+ format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
+ ),
+ (Some(_), Some((_, []))) => (
+ hir_generics.span.shrink_to_hi(),
+ format!(": {}", trait_pred.print_modifiers_and_trait_path()),
+ ),
+ };
+
+ err.span_suggestion_verbose(
+ sp,
+ &format!("consider further restricting {}", msg),
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+ }
+}
+
+impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+ fn suggest_restricting_param_bound(
+ &self,
+ mut err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ proj_pred: Option<ty::PolyProjectionPredicate<'tcx>>,
+ body_id: hir::HirId,
+ ) {
+ let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
+
+ let self_ty = trait_pred.skip_binder().self_ty();
+ let (param_ty, projection) = match self_ty.kind() {
+ ty::Param(_) => (true, None),
+ ty::Projection(projection) => (false, Some(projection)),
+ _ => (false, None),
+ };
+
+ // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
+ // don't suggest `T: Sized + ?Sized`.
+ let mut hir_id = body_id;
+ while let Some(node) = self.tcx.hir().find(hir_id) {
+ match node {
+ hir::Node::Item(hir::Item {
+ ident,
+ kind: hir::ItemKind::Trait(_, _, generics, bounds, _),
+ ..
+ }) if self_ty == self.tcx.types.self_param => {
+ assert!(param_ty);
+ // Restricting `Self` for a single method.
+ suggest_restriction(
+ self.tcx,
+ hir_id,
+ &generics,
+ "`Self`",
+ err,
+ None,
+ projection,
+ trait_pred,
+ Some((ident, bounds)),
+ );
+ return;
+ }
+
+ hir::Node::TraitItem(hir::TraitItem {
+ generics,
+ kind: hir::TraitItemKind::Fn(..),
+ ..
+ }) if self_ty == self.tcx.types.self_param => {
+ assert!(param_ty);
+ // Restricting `Self` for a single method.
+ suggest_restriction(
+ self.tcx, hir_id, &generics, "`Self`", err, None, projection, trait_pred,
+ None,
+ );
+ return;
+ }
+
+ hir::Node::TraitItem(hir::TraitItem {
+ generics,
+ kind: hir::TraitItemKind::Fn(fn_sig, ..),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ generics,
+ kind: hir::ImplItemKind::Fn(fn_sig, ..),
+ ..
+ })
+ | hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Fn(fn_sig, generics, _), ..
+ }) if projection.is_some() => {
+ // Missing restriction on associated type of type parameter (unmet projection).
+ suggest_restriction(
+ self.tcx,
+ hir_id,
+ &generics,
+ "the associated type",
+ err,
+ Some(fn_sig),
+ projection,
+ trait_pred,
+ None,
+ );
+ return;
+ }
+ hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Trait(_, _, generics, ..)
+ | hir::ItemKind::Impl(hir::Impl { generics, .. }),
+ ..
+ }) if projection.is_some() => {
+ // Missing restriction on associated type of type parameter (unmet projection).
+ suggest_restriction(
+ self.tcx,
+ hir_id,
+ &generics,
+ "the associated type",
+ err,
+ None,
+ projection,
+ trait_pred,
+ None,
+ );
+ return;
+ }
+
+ hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Struct(_, generics)
+ | hir::ItemKind::Enum(_, generics)
+ | hir::ItemKind::Union(_, generics)
+ | hir::ItemKind::Trait(_, _, generics, ..)
+ | hir::ItemKind::Impl(hir::Impl { generics, .. })
+ | hir::ItemKind::Fn(_, generics, _)
+ | hir::ItemKind::TyAlias(_, generics)
+ | hir::ItemKind::TraitAlias(generics, _)
+ | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+ ..
+ })
+ | hir::Node::TraitItem(hir::TraitItem { generics, .. })
+ | hir::Node::ImplItem(hir::ImplItem { generics, .. })
+ if param_ty =>
+ {
+ // We skip the 0'th subst (self) because we do not want
+ // to consider the predicate as not suggestible if the
+ // self type is an arg position `impl Trait` -- instead,
+ // we handle that by adding ` + Bound` below.
+ // FIXME(compiler-errors): It would be nice to do the same
+ // this that we do in `suggest_restriction` and pull the
+ // `impl Trait` into a new generic if it shows up somewhere
+ // else in the predicate.
+ if !trait_pred.skip_binder().trait_ref.substs[1..]
+ .iter()
+ .all(|g| g.is_suggestable(self.tcx, false))
+ {
+ return;
+ }
+ // Missing generic type parameter bound.
+ let param_name = self_ty.to_string();
+ let mut constraint = with_no_trimmed_paths!(
+ trait_pred.print_modifiers_and_trait_path().to_string()
+ );
+
+ if let Some(proj_pred) = proj_pred {
+ let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder();
+ let item = self.tcx.associated_item(projection_ty.item_def_id);
+
+ // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err.
+ // That should be extracted into a helper function.
+ if constraint.ends_with('>') {
+ constraint = format!(
+ "{}, {}={}>",
+ &constraint[..constraint.len() - 1],
+ item.name,
+ term
+ );
+ } else {
+ constraint.push_str(&format!("<{}={}>", item.name, term));
+ }
+ }
+
+ if suggest_constraining_type_param(
+ self.tcx,
+ generics,
+ &mut err,
+ &param_name,
+ &constraint,
+ Some(trait_pred.def_id()),
+ ) {
+ return;
+ }
+ }
+
+ hir::Node::Item(hir::Item {
+ kind:
+ hir::ItemKind::Struct(_, generics)
+ | hir::ItemKind::Enum(_, generics)
+ | hir::ItemKind::Union(_, generics)
+ | hir::ItemKind::Trait(_, _, generics, ..)
+ | hir::ItemKind::Impl(hir::Impl { generics, .. })
+ | hir::ItemKind::Fn(_, generics, _)
+ | hir::ItemKind::TyAlias(_, generics)
+ | hir::ItemKind::TraitAlias(generics, _)
+ | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+ ..
+ }) if !param_ty => {
+ // Missing generic type parameter bound.
+ if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) {
+ return;
+ }
+ }
+ hir::Node::Crate(..) => return,
+
+ _ => {}
+ }
+
+ hir_id = self.tcx.hir().local_def_id_to_hir_id(self.tcx.hir().get_parent_item(hir_id));
+ }
+ }
+
+ /// When after several dereferencing, the reference satisfies the trait
+ /// binding. This function provides dereference suggestion for this
+ /// specific situation.
+ fn suggest_dereferences(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ // It only make sense when suggesting dereferences for arguments
+ let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else {
+ return false;
+ };
+ let param_env = obligation.param_env;
+ let body_id = obligation.cause.body_id;
+ let span = obligation.cause.span;
+ let mut real_trait_pred = trait_pred;
+ let mut code = obligation.cause.code();
+ while let Some((parent_code, parent_trait_pred)) = code.parent() {
+ code = parent_code;
+ if let Some(parent_trait_pred) = parent_trait_pred {
+ real_trait_pred = parent_trait_pred;
+ }
+
+ // Skipping binder here, remapping below
+ let real_ty = real_trait_pred.self_ty().skip_binder();
+
+ if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
+ let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
+ if let Some(steps) = autoderef.find_map(|(ty, steps)| {
+ // Re-add the `&`
+ let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+
+ // Remapping bound vars here
+ let real_trait_pred_and_ty =
+ real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
+ let obligation = self
+ .mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
+ Some(steps).filter(|_| self.predicate_may_hold(&obligation))
+ }) {
+ if steps > 0 {
+ if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // Don't care about `&mut` because `DerefMut` is used less
+ // often and user will not expect autoderef happens.
+ if src.starts_with('&') && !src.starts_with("&mut ") {
+ let derefs = "*".repeat(steps);
+ err.span_suggestion(
+ span,
+ "consider dereferencing here",
+ format!("&{}{}", derefs, &src[1..]),
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ }
+ }
+ } else if real_trait_pred != trait_pred {
+ // This branch addresses #87437.
+
+ // Remapping bound vars here
+ let real_trait_pred_and_base_ty =
+ real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
+ let obligation = self.mk_trait_obligation_with_new_self_ty(
+ param_env,
+ real_trait_pred_and_base_ty,
+ );
+ if self.predicate_may_hold(&obligation) {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider dereferencing here",
+ "*",
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ }
+ }
+ }
+ false
+ }
+
+ /// Given a closure's `DefId`, return the given name of the closure.
+ ///
+ /// This doesn't account for reassignments, but it's only used for suggestions.
+ fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option<Symbol> {
+ let get_name = |err: &mut Diagnostic, kind: &hir::PatKind<'_>| -> Option<Symbol> {
+ // Get the local name of this closure. This can be inaccurate because
+ // of the possibility of reassignment, but this should be good enough.
+ match &kind {
+ hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) => {
+ Some(ident.name)
+ }
+ _ => {
+ err.note(msg);
+ None
+ }
+ }
+ };
+
+ let hir = self.tcx.hir();
+ let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?);
+ let parent_node = hir.get_parent_node(hir_id);
+ match hir.find(parent_node) {
+ Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
+ get_name(err, &local.pat.kind)
+ }
+ // Different to previous arm because one is `&hir::Local` and the other
+ // is `P<hir::Local>`.
+ Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind),
+ _ => None,
+ }
+ }
+
+ /// We tried to apply the bound to an `fn` or closure. Check whether calling it would
+ /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
+ /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
+ fn suggest_fn_call(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ // Skipping binder here, remapping below
+ let self_ty = trait_pred.self_ty().skip_binder();
+
+ let (def_id, output_ty, callable) = match *self_ty.kind() {
+ ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
+ ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"),
+ _ => return false,
+ };
+ let msg = format!("use parentheses to call the {}", callable);
+
+ // "We should really create a single list of bound vars from the combined vars
+ // from the predicate and function, but instead we just liberate the function bound vars"
+ let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
+
+ // Remapping bound vars here
+ let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
+
+ let new_obligation =
+ self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
+
+ match self.evaluate_obligation(&new_obligation) {
+ Ok(
+ EvaluationResult::EvaluatedToOk
+ | EvaluationResult::EvaluatedToOkModuloRegions
+ | EvaluationResult::EvaluatedToOkModuloOpaqueTypes
+ | EvaluationResult::EvaluatedToAmbig,
+ ) => {}
+ _ => return false,
+ }
+ let hir = self.tcx.hir();
+ // Get the name of the callable and the arguments to be used in the suggestion.
+ let (snippet, sugg) = match hir.get_if_local(def_id) {
+ Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(hir::Closure { fn_decl, fn_decl_span, .. }),
+ ..
+ })) => {
+ err.span_label(*fn_decl_span, "consider calling this closure");
+ let Some(name) = self.get_closure_name(def_id, err, &msg) else {
+ return false;
+ };
+ let args = fn_decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
+ let sugg = format!("({})", args);
+ (format!("{}{}", name, sugg), sugg)
+ }
+ Some(hir::Node::Item(hir::Item {
+ ident,
+ kind: hir::ItemKind::Fn(.., body_id),
+ ..
+ })) => {
+ err.span_label(ident.span, "consider calling this function");
+ let body = hir.body(*body_id);
+ let args = body
+ .params
+ .iter()
+ .map(|arg| match &arg.pat.kind {
+ hir::PatKind::Binding(_, _, ident, None)
+ // FIXME: provide a better suggestion when encountering `SelfLower`, it
+ // should suggest a method call.
+ if ident.name != kw::SelfLower => ident.to_string(),
+ _ => "_".to_string(),
+ })
+ .collect::<Vec<_>>()
+ .join(", ");
+ let sugg = format!("({})", args);
+ (format!("{}{}", ident, sugg), sugg)
+ }
+ _ => return false,
+ };
+ if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
+ {
+ // When the obligation error has been ensured to have been caused by
+ // an argument, the `obligation.cause.span` points at the expression
+ // of the argument, so we can provide a suggestion. Otherwise, we give
+ // a more general note.
+ err.span_suggestion_verbose(
+ obligation.cause.span.shrink_to_hi(),
+ &msg,
+ sugg,
+ Applicability::HasPlaceholders,
+ );
+ } else {
+ err.help(&format!("{}: `{}`", msg, snippet));
+ }
+ true
+ }
+
+ fn suggest_add_reference_to_arg(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ poly_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ has_custom_message: bool,
+ ) -> bool {
+ let span = obligation.cause.span;
+
+ let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
+ obligation.cause.code()
+ {
+ &parent_code
+ } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
+ span.ctxt().outer_expn_data().kind
+ {
+ obligation.cause.code()
+ } else {
+ return false;
+ };
+
+ // List of traits for which it would be nonsensical to suggest borrowing.
+ // For instance, immutable references are always Copy, so suggesting to
+ // borrow would always succeed, but it's probably not what the user wanted.
+ let mut never_suggest_borrow: Vec<_> =
+ [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]
+ .iter()
+ .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
+ .collect();
+
+ if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
+ never_suggest_borrow.push(def_id);
+ }
+
+ let param_env = obligation.param_env;
+
+ // Try to apply the original trait binding obligation by borrowing.
+ let mut try_borrowing =
+ |old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
+ if blacklist.contains(&old_pred.def_id()) {
+ return false;
+ }
+ // We map bounds to `&T` and `&mut T`
+ let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
+ (
+ trait_pred,
+ self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ )
+ });
+ let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
+ (
+ trait_pred,
+ self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
+ )
+ });
+
+ let mk_result = |trait_pred_and_new_ty| {
+ let obligation =
+ self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
+ self.predicate_must_hold_modulo_regions(&obligation)
+ };
+ let imm_result = mk_result(trait_pred_and_imm_ref);
+ let mut_result = mk_result(trait_pred_and_mut_ref);
+
+ if imm_result || mut_result {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ // We have a very specific type of error, where just borrowing this argument
+ // might solve the problem. In cases like this, the important part is the
+ // original type obligation, not the last one that failed, which is arbitrary.
+ // Because of this, we modify the error to refer to the original obligation and
+ // return early in the caller.
+
+ let msg = format!("the trait bound `{}` is not satisfied", old_pred);
+ if has_custom_message {
+ err.note(&msg);
+ } else {
+ err.message =
+ vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
+ }
+ if snippet.starts_with('&') {
+ // This is already a literal borrow and the obligation is failing
+ // somewhere else in the obligation chain. Do not suggest non-sense.
+ return false;
+ }
+ err.span_label(
+ span,
+ &format!(
+ "expected an implementor of trait `{}`",
+ old_pred.print_modifiers_and_trait_path(),
+ ),
+ );
+
+ // This if is to prevent a special edge-case
+ if matches!(
+ span.ctxt().outer_expn_data().kind,
+ ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
+ ) {
+ // We don't want a borrowing suggestion on the fields in structs,
+ // ```
+ // struct Foo {
+ // the_foos: Vec<Foo>
+ // }
+ // ```
+
+ if imm_result && mut_result {
+ err.span_suggestions(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ ["&".to_string(), "&mut ".to_string()].into_iter(),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!(
+ "consider{} borrowing here",
+ if mut_result { " mutably" } else { "" }
+ ),
+ format!("&{}", if mut_result { "mut " } else { "" }),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ };
+
+ if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
+ try_borrowing(cause.derived.parent_trait_pred, &[])
+ } else if let ObligationCauseCode::BindingObligation(_, _)
+ | ObligationCauseCode::ItemObligation(_) = code
+ {
+ try_borrowing(poly_trait_pred, &never_suggest_borrow)
+ } else {
+ false
+ }
+ }
+
+ // Suggest borrowing the type
+ fn suggest_borrowing_for_object_cast(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ self_ty: Ty<'tcx>,
+ object_ty: Ty<'tcx>,
+ ) {
+ let ty::Dynamic(predicates, _) = object_ty.kind() else { return; };
+ let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
+
+ for predicate in predicates.iter() {
+ if !self.predicate_must_hold_modulo_regions(
+ &obligation.with(predicate.with_self_ty(self.tcx, self_ref_ty)),
+ ) {
+ return;
+ }
+ }
+
+ err.span_suggestion(
+ obligation.cause.span.shrink_to_lo(),
+ &format!(
+ "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
+ ),
+ "&",
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
+ /// suggest removing these references until we reach a type that implements the trait.
+ fn suggest_remove_reference(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ let span = obligation.cause.span;
+
+ let mut suggested = false;
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ let refs_number =
+ snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
+ if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
+ // Do not suggest removal of borrow from type arguments.
+ return false;
+ }
+
+ // Skipping binder here, remapping below
+ let mut suggested_ty = trait_pred.self_ty().skip_binder();
+
+ for refs_remaining in 0..refs_number {
+ let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
+ break;
+ };
+ suggested_ty = *inner_ty;
+
+ // Remapping bound vars here
+ let trait_pred_and_suggested_ty =
+ trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
+ let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env,
+ trait_pred_and_suggested_ty,
+ );
+
+ if self.predicate_may_hold(&new_obligation) {
+ let sp = self
+ .tcx
+ .sess
+ .source_map()
+ .span_take_while(span, |c| c.is_whitespace() || *c == '&');
+
+ let remove_refs = refs_remaining + 1;
+
+ let msg = if remove_refs == 1 {
+ "consider removing the leading `&`-reference".to_string()
+ } else {
+ format!("consider removing {} leading `&`-references", remove_refs)
+ };
+
+ err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable);
+ suggested = true;
+ break;
+ }
+ }
+ }
+ suggested
+ }
+
+ fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
+ let span = obligation.cause.span;
+
+ if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() {
+ let hir = self.tcx.hir();
+ if let Some(node) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
+ if let hir::Node::Expr(expr) = node {
+ // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
+ // and if not maybe suggest doing something else? If we kept the expression around we
+ // could also check if it is an fn call (very likely) and suggest changing *that*, if
+ // it is from the local crate.
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_hi().with_hi(span.hi()),
+ "remove the `.await`",
+ "",
+ Applicability::MachineApplicable,
+ );
+ // FIXME: account for associated `async fn`s.
+ if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
+ if let ty::PredicateKind::Trait(pred) =
+ obligation.predicate.kind().skip_binder()
+ {
+ err.span_label(
+ *span,
+ &format!("this call returns `{}`", pred.self_ty()),
+ );
+ }
+ if let Some(typeck_results) =
+ self.in_progress_typeck_results.map(|t| t.borrow())
+ && let ty = typeck_results.expr_ty_adjusted(base)
+ && let ty::FnDef(def_id, _substs) = ty.kind()
+ && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
+ hir.get_if_local(*def_id)
+ {
+ let msg = format!(
+ "alternatively, consider making `fn {}` asynchronous",
+ ident
+ );
+ 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,
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /// Check if the trait bound is implemented for a different mutability and note it in the
+ /// final error.
+ fn suggest_change_mut(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) {
+ let points_at_arg = matches!(
+ obligation.cause.code(),
+ ObligationCauseCode::FunctionArgumentObligation { .. },
+ );
+
+ let span = obligation.cause.span;
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ let refs_number =
+ snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
+ if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
+ // Do not suggest removal of borrow from type arguments.
+ return;
+ }
+ let trait_pred = self.resolve_vars_if_possible(trait_pred);
+ if trait_pred.has_infer_types_or_consts() {
+ // Do not ICE while trying to find if a reborrow would succeed on a trait with
+ // unresolved bindings.
+ return;
+ }
+
+ // Skipping binder here, remapping below
+ if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
+ {
+ let suggested_ty = match mutability {
+ hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type),
+ hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
+ };
+
+ // Remapping bound vars here
+ let trait_pred_and_suggested_ty =
+ trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
+ let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env,
+ trait_pred_and_suggested_ty,
+ );
+ let suggested_ty_would_satisfy_obligation = self
+ .evaluate_obligation_no_overflow(&new_obligation)
+ .must_apply_modulo_regions();
+ if suggested_ty_would_satisfy_obligation {
+ let sp = self
+ .tcx
+ .sess
+ .source_map()
+ .span_take_while(span, |c| c.is_whitespace() || *c == '&');
+ if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 {
+ err.span_suggestion_verbose(
+ sp,
+ "consider changing this borrow's mutability",
+ "&mut ",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.note(&format!(
+ "`{}` is implemented for `{:?}`, but not for `{:?}`",
+ trait_pred.print_modifiers_and_trait_path(),
+ suggested_ty,
+ trait_pred.skip_binder().self_ty(),
+ ));
+ }
+ }
+ }
+ }
+ }
+
+ fn suggest_semicolon_removal(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ let hir = self.tcx.hir();
+ let parent_node = hir.get_parent_node(obligation.cause.body_id);
+ let node = hir.find(parent_node);
+ if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node
+ && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
+ && sig.decl.output.span().overlaps(span)
+ && blk.expr.is_none()
+ && trait_pred.self_ty().skip_binder().is_unit()
+ && let Some(stmt) = blk.stmts.last()
+ && let hir::StmtKind::Semi(expr) = stmt.kind
+ // Only suggest this if the expression behind the semicolon implements the predicate
+ && let Some(typeck_results) = self.in_progress_typeck_results
+ && let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
+ && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
+ ))
+ {
+ err.span_label(
+ expr.span,
+ &format!(
+ "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
+ );
+ return true;
+ }
+ false
+ }
+
+ fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
+ let hir = self.tcx.hir();
+ let parent_node = hir.get_parent_node(obligation.cause.body_id);
+ let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = hir.find(parent_node) else {
+ return None;
+ };
+
+ if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { Some(ret_ty.span) } else { None }
+ }
+
+ /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
+ /// applicable and signal that the error has been expanded appropriately and needs to be
+ /// emitted.
+ fn suggest_impl_trait(
+ &self,
+ err: &mut Diagnostic,
+ span: Span,
+ obligation: &PredicateObligation<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ match obligation.cause.code().peel_derives() {
+ // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
+ ObligationCauseCode::SizedReturnType => {}
+ _ => return false,
+ }
+
+ let hir = self.tcx.hir();
+ let fn_hir_id = hir.get_parent_node(obligation.cause.body_id);
+ let node = hir.find(fn_hir_id);
+ let Some(hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Fn(sig, _, body_id),
+ ..
+ })) = node
+ else {
+ return false;
+ };
+ let body = hir.body(*body_id);
+ let trait_pred = self.resolve_vars_if_possible(trait_pred);
+ let ty = trait_pred.skip_binder().self_ty();
+ let is_object_safe = match ty.kind() {
+ ty::Dynamic(predicates, _) => {
+ // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
+ predicates
+ .principal_def_id()
+ .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
+ }
+ // We only want to suggest `impl Trait` to `dyn Trait`s.
+ // For example, `fn foo() -> str` needs to be filtered out.
+ _ => return false,
+ };
+
+ let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
+ return false;
+ };
+
+ // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
+ // cases like `fn foo() -> (dyn Trait, i32) {}`.
+ // Recursively look for `TraitObject` types and if there's only one, use that span to
+ // suggest `impl Trait`.
+
+ // Visit to make sure there's a single `return` type to suggest `impl Trait`,
+ // otherwise suggest using `Box<dyn Trait>` or an enum.
+ let mut visitor = ReturnsVisitor::default();
+ visitor.visit_body(&body);
+
+ let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
+ let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
+
+ let ret_types = visitor
+ .returns
+ .iter()
+ .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?)))
+ .map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty)));
+ let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
+ (None, true, true),
+ |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
+ (_, ty)| {
+ let ty = self.resolve_vars_if_possible(ty);
+ same &=
+ !matches!(ty.kind(), ty::Error(_))
+ && last_ty.map_or(true, |last_ty| {
+ // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
+ // *after* in the dependency graph.
+ match (ty.kind(), last_ty.kind()) {
+ (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_)))
+ | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_)))
+ | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_)))
+ | (
+ Infer(InferTy::FreshFloatTy(_)),
+ Infer(InferTy::FreshFloatTy(_)),
+ ) => true,
+ _ => ty == last_ty,
+ }
+ });
+ (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never))
+ },
+ );
+ let mut spans_and_needs_box = vec![];
+
+ match liberated_sig.output().kind() {
+ ty::Dynamic(predicates, _) => {
+ let cause = ObligationCause::misc(ret_ty.span, fn_hir_id);
+ let param_env = ty::ParamEnv::empty();
+
+ if !only_never_return {
+ for (expr_span, return_ty) in ret_types {
+ let self_ty_satisfies_dyn_predicates = |self_ty| {
+ predicates.iter().all(|predicate| {
+ let pred = predicate.with_self_ty(self.tcx, self_ty);
+ let obl = Obligation::new(cause.clone(), param_env, pred);
+ self.predicate_may_hold(&obl)
+ })
+ };
+
+ if let ty::Adt(def, substs) = return_ty.kind()
+ && def.is_box()
+ && self_ty_satisfies_dyn_predicates(substs.type_at(0))
+ {
+ spans_and_needs_box.push((expr_span, false));
+ } else if self_ty_satisfies_dyn_predicates(return_ty) {
+ spans_and_needs_box.push((expr_span, true));
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ _ => return false,
+ };
+
+ let sm = self.tcx.sess.source_map();
+ if !ret_ty.span.overlaps(span) {
+ return false;
+ }
+ let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind {
+ if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) {
+ snippet
+ } else {
+ return false;
+ }
+ } else {
+ // Substitute the type, so we can print a fixup given `type Alias = dyn Trait`
+ let name = liberated_sig.output().to_string();
+ let name =
+ name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name);
+ if !name.starts_with("dyn ") {
+ return false;
+ }
+ name.to_owned()
+ };
+
+ err.code(error_code!(E0746));
+ err.set_primary_message("return type cannot have an unboxed trait object");
+ err.children.clear();
+ let impl_trait_msg = "for information on `impl Trait`, see \
+ <https://doc.rust-lang.org/book/ch10-02-traits.html\
+ #returning-types-that-implement-traits>";
+ let trait_obj_msg = "for information on trait objects, see \
+ <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
+ #using-trait-objects-that-allow-for-values-of-different-types>";
+
+ let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
+ let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
+ if only_never_return {
+ // No return paths, probably using `panic!()` or similar.
+ // Suggest `-> T`, `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
+ suggest_trait_object_return_type_alternatives(
+ err,
+ ret_ty.span,
+ trait_obj,
+ is_object_safe,
+ );
+ } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) {
+ // Suggest `-> impl Trait`.
+ err.span_suggestion(
+ ret_ty.span,
+ &format!(
+ "use `impl {1}` as the return type, as all return paths are of type `{}`, \
+ which implements `{1}`",
+ last_ty, trait_obj,
+ ),
+ format!("impl {}", trait_obj),
+ Applicability::MachineApplicable,
+ );
+ err.note(impl_trait_msg);
+ } else {
+ if is_object_safe {
+ // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
+ err.multipart_suggestion(
+ "return a boxed trait object instead",
+ vec![
+ (ret_ty.span.shrink_to_lo(), "Box<".to_string()),
+ (span.shrink_to_hi(), ">".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ for (span, needs_box) in spans_and_needs_box {
+ if needs_box {
+ err.multipart_suggestion(
+ "... and box this value",
+ vec![
+ (span.shrink_to_lo(), "Box::new(".to_string()),
+ (span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ } else {
+ // This is currently not possible to trigger because E0038 takes precedence, but
+ // leave it in for completeness in case anything changes in an earlier stage.
+ err.note(&format!(
+ "if trait `{}` were object-safe, you could return a trait object",
+ trait_obj,
+ ));
+ }
+ err.note(trait_obj_msg);
+ err.note(&format!(
+ "if all the returned values were of the same type you could use `impl {}` as the \
+ return type",
+ trait_obj,
+ ));
+ err.note(impl_trait_msg);
+ err.note("you can create a new `enum` with a variant for each returned type");
+ }
+ true
+ }
+
+ fn point_at_returns_when_relevant(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ ) {
+ match obligation.cause.code().peel_derives() {
+ ObligationCauseCode::SizedReturnType => {}
+ _ => return,
+ }
+
+ let hir = self.tcx.hir();
+ let parent_node = hir.get_parent_node(obligation.cause.body_id);
+ let node = hir.find(parent_node);
+ if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) =
+ node
+ {
+ let body = hir.body(*body_id);
+ // Point at all the `return`s in the function as they have failed trait bounds.
+ let mut visitor = ReturnsVisitor::default();
+ visitor.visit_body(&body);
+ let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
+ for expr in &visitor.returns {
+ if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) {
+ let ty = self.resolve_vars_if_possible(returned_ty);
+ err.span_label(expr.span, &format!("this returned value is of type `{}`", ty));
+ }
+ }
+ }
+ }
+
+ fn report_closure_arg_mismatch(
+ &self,
+ span: Span,
+ found_span: Option<Span>,
+ found: ty::PolyTraitRef<'tcx>,
+ expected: ty::PolyTraitRef<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ pub(crate) fn build_fn_sig_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Ty<'tcx> {
+ let inputs = trait_ref.skip_binder().substs.type_at(1);
+ let sig = match inputs.kind() {
+ ty::Tuple(inputs)
+ if tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some() =>
+ {
+ tcx.mk_fn_sig(
+ inputs.iter(),
+ tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+ false,
+ hir::Unsafety::Normal,
+ abi::Abi::Rust,
+ )
+ }
+ _ => tcx.mk_fn_sig(
+ std::iter::once(inputs),
+ tcx.mk_ty_infer(ty::TyVar(ty::TyVid::from_u32(0))),
+ false,
+ hir::Unsafety::Normal,
+ abi::Abi::Rust,
+ ),
+ };
+
+ tcx.mk_fn_ptr(trait_ref.rebind(sig))
+ }
+
+ let argument_kind = match expected.skip_binder().self_ty().kind() {
+ ty::Closure(..) => "closure",
+ ty::Generator(..) => "generator",
+ _ => "function",
+ };
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0631,
+ "type mismatch in {argument_kind} arguments",
+ );
+
+ err.span_label(span, "expected due to this");
+
+ let found_span = found_span.unwrap_or(span);
+ err.span_label(found_span, "found signature defined here");
+
+ let expected = build_fn_sig_ty(self.tcx, expected);
+ let found = build_fn_sig_ty(self.tcx, found);
+
+ let (expected_str, found_str) =
+ self.tcx.infer_ctxt().enter(|infcx| infcx.cmp(expected, found));
+
+ let signature_kind = format!("{argument_kind} signature");
+ err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str);
+
+ err
+ }
+
+ fn suggest_fully_qualified_path(
+ &self,
+ err: &mut Diagnostic,
+ item_def_id: DefId,
+ span: Span,
+ trait_ref: DefId,
+ ) {
+ if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
+ if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
+ err.note(&format!(
+ "{}s cannot be accessed directly on a `trait`, they can only be \
+ accessed through a specific `impl`",
+ assoc_item.kind.as_def_kind().descr(item_def_id)
+ ));
+ err.span_suggestion(
+ span,
+ "use the fully qualified path to an implementation",
+ format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name),
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+ }
+
+ /// Adds an async-await specific note to the diagnostic when the future does not implement
+ /// an auto trait because of a captured type.
+ ///
+ /// ```text
+ /// note: future does not implement `Qux` as this value is used across an await
+ /// --> $DIR/issue-64130-3-other.rs:17:5
+ /// |
+ /// LL | let x = Foo;
+ /// | - has type `Foo`
+ /// LL | baz().await;
+ /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ /// LL | }
+ /// | - `x` is later dropped here
+ /// ```
+ ///
+ /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic
+ /// is "replaced" with a different message and a more specific error.
+ ///
+ /// ```text
+ /// error: future cannot be sent between threads safely
+ /// --> $DIR/issue-64130-2-send.rs:21:5
+ /// |
+ /// LL | fn is_send<T: Send>(t: T) { }
+ /// | ---- required by this bound in `is_send`
+ /// ...
+ /// LL | is_send(bar());
+ /// | ^^^^^^^ future returned by `bar` is not send
+ /// |
+ /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not
+ /// implemented for `Foo`
+ /// note: future is not send as this value is used across an await
+ /// --> $DIR/issue-64130-2-send.rs:15:5
+ /// |
+ /// LL | let x = Foo;
+ /// | - has type `Foo`
+ /// LL | baz().await;
+ /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later
+ /// LL | }
+ /// | - `x` is later dropped here
+ /// ```
+ ///
+ /// Returns `true` if an async-await specific note was added to the diagnostic.
+ #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))]
+ fn maybe_note_obligation_cause_for_async_await(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> bool {
+ 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.
+ //
+ // 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.
+ //
+ // 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 `std::future::GenFuture` (B)
+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (B)
+ // - `BuiltinDerivedObligation` with a generator witness (A)
+ // - `BuiltinDerivedObligation` with a generator (A)
+ // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A)
+ // - `BuiltinDerivedObligation` with `impl std::future::Future` (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
+ // modified.
+ let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(p) => (Some(p), Some(p.self_ty())),
+ _ => (None, None),
+ };
+ let mut generator = None;
+ let mut outer_generator = None;
+ let mut next_code = Some(obligation.cause.code());
+
+ let mut seen_upvar_tys_infer_tuple = false;
+
+ while let Some(code) = next_code {
+ debug!(?code);
+ match code {
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ next_code = Some(parent_code);
+ }
+ ObligationCauseCode::ImplDerivedObligation(cause) => {
+ let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
+ debug!(
+ parent_trait_ref = ?cause.derived.parent_trait_pred,
+ self_ty.kind = ?ty.kind(),
+ "ImplDerived",
+ );
+
+ match *ty.kind() {
+ ty::Generator(did, ..) => {
+ generator = generator.or(Some(did));
+ outer_generator = Some(did);
+ }
+ ty::GeneratorWitness(..) => {}
+ 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,
+ // we shall ignore this.
+
+ seen_upvar_tys_infer_tuple = true;
+ }
+ _ if generator.is_none() => {
+ trait_ref = Some(cause.derived.parent_trait_pred.skip_binder());
+ target_ty = Some(ty);
+ }
+ _ => {}
+ }
+
+ next_code = Some(&cause.derived.parent_code);
+ }
+ ObligationCauseCode::DerivedObligation(derived_obligation)
+ | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => {
+ let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
+ debug!(
+ parent_trait_ref = ?derived_obligation.parent_trait_pred,
+ self_ty.kind = ?ty.kind(),
+ );
+
+ match *ty.kind() {
+ ty::Generator(did, ..) => {
+ generator = generator.or(Some(did));
+ outer_generator = Some(did);
+ }
+ ty::GeneratorWitness(..) => {}
+ 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,
+ // we shall ignore this.
+
+ seen_upvar_tys_infer_tuple = true;
+ }
+ _ if generator.is_none() => {
+ trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder());
+ target_ty = Some(ty);
+ }
+ _ => {}
+ }
+
+ next_code = Some(&derived_obligation.parent_code);
+ }
+ _ => break,
+ }
+ }
+
+ // 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) else {
+ return false;
+ };
+
+ let span = self.tcx.def_span(generator_did);
+
+ let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
+ let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
+ debug!(
+ ?generator_did,
+ ?generator_did_root,
+ in_progress_typeck_results.hir_owner = ?in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
+ ?span,
+ );
+
+ let generator_body = generator_did
+ .as_local()
+ .and_then(|def_id| hir.maybe_body_owned_by(def_id))
+ .map(|body_id| hir.body(body_id));
+ let is_async = match generator_did.as_local() {
+ Some(_) => generator_body
+ .and_then(|body| body.generator_kind())
+ .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+ .unwrap_or(false),
+ None => self
+ .tcx
+ .generator_kind(generator_did)
+ .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..)))
+ .unwrap_or(false),
+ };
+ let mut visitor = AwaitsVisitor::default();
+ if let Some(body) = generator_body {
+ visitor.visit_body(body);
+ }
+ debug!(awaits = ?visitor.awaits);
+
+ // Look for a type inside the generator 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
+ // 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
+ // interior generally contain "bound regions" to
+ // represent regions that are part of the suspended
+ // generator 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);
+ let ty_erased = self.tcx.erase_regions(ty_erased);
+ let eq = ty_erased == target_ty_erased;
+ debug!(?ty_erased, ?target_ty_erased, ?eq);
+ eq
+ };
+
+ let mut interior_or_upvar_span = None;
+ let mut interior_extra_info = None;
+
+ // Get the typeck results from the infcx if the generator 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,
+ // we still provide a targeted error but without all the relevant spans.
+ let generator_data: Option<GeneratorData<'tcx, '_>> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => {
+ Some(GeneratorData::Local(&t))
+ }
+ _ if generator_did.is_local() => {
+ Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())))
+ }
+ _ => self
+ .tcx
+ .generator_diagnostic_data(generator_did)
+ .as_ref()
+ .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)),
+ };
+
+ if let Some(generator_data) = generator_data.as_ref() {
+ interior_or_upvar_span =
+ generator_data.try_get_upvar_span(&self, generator_did, ty_matches);
+
+ // The generator interior types share the same binders
+ if let Some(cause) =
+ generator_data.get_generator_interior_types().skip_binder().iter().find(
+ |ty::GeneratorInteriorTypeCause { ty, .. }| {
+ ty_matches(generator_data.get_generator_interior_types().rebind(*ty))
+ },
+ )
+ {
+ let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
+ let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
+ cause;
+
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
+ interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
+ }
+
+ if interior_or_upvar_span.is_none() && generator_data.is_foreign() {
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
+ }
+
+ if let Some(interior_or_upvar_span) = interior_or_upvar_span {
+ let typeck_results = generator_data.and_then(|generator_data| match generator_data {
+ GeneratorData::Local(typeck_results) => Some(typeck_results),
+ GeneratorData::Foreign(_) => None,
+ });
+ self.note_obligation_cause_for_async_await(
+ err,
+ interior_or_upvar_span,
+ interior_extra_info,
+ is_async,
+ outer_generator,
+ trait_ref,
+ target_ty,
+ typeck_results,
+ obligation,
+ next_code,
+ );
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Unconditionally adds the diagnostic note described in
+ /// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
+ #[instrument(level = "debug", skip_all)]
+ fn note_obligation_cause_for_async_await(
+ &self,
+ err: &mut Diagnostic,
+ interior_or_upvar_span: GeneratorInteriorOrUpvar,
+ interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
+ is_async: bool,
+ outer_generator: Option<DefId>,
+ trait_pred: ty::TraitPredicate<'tcx>,
+ target_ty: Ty<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
+ obligation: &PredicateObligation<'tcx>,
+ next_code: Option<&ObligationCauseCode<'tcx>>,
+ ) {
+ let source_map = self.tcx.sess.source_map();
+
+ 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" };
+
+ // Special case the primary error message when send or sync is the trait that was
+ // not implemented.
+ let hir = self.tcx.hir();
+ let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
+ self.tcx.get_diagnostic_name(trait_pred.def_id())
+ {
+ let (trait_name, trait_verb) =
+ if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
+
+ err.clear_code();
+ err.set_primary_message(format!(
+ "{} cannot be {} between threads safely",
+ future_or_generator, trait_verb
+ ));
+
+ 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
+ .tcx
+ .parent(generator_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 `{}` is not {}", name, trait_name)
+ })?,
+ GeneratorKind::Async(AsyncGeneratorKind::Block) => {
+ format!("future created by async block is not {}", trait_name)
+ }
+ GeneratorKind::Async(AsyncGeneratorKind::Closure) => {
+ format!("future created by async closure is not {}", trait_name)
+ }
+ })
+ })
+ .unwrap_or_else(|| format!("{} is not {}", future_or_generator, trait_name));
+
+ span.push_span_label(original_span, message);
+ err.set_span(span);
+
+ format!("is not {}", trait_name)
+ } else {
+ format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
+ };
+
+ let mut explain_yield = |interior_span: Span,
+ yield_span: Span,
+ scope_span: Option<Span>| {
+ let mut span = MultiSpan::from_span(yield_span);
+ if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
+ // #70935: If snippet contains newlines, display "the value" instead
+ // so that we do not emit complex diagnostics.
+ let snippet = &format!("`{}`", snippet);
+ let snippet = if snippet.contains('\n') { "the value" } else { snippet };
+ // note: future is not `Send` as this value is used across an await
+ // --> $DIR/issue-70935-complex-spans.rs:13:9
+ // |
+ // LL | baz(|| async {
+ // | ______________-
+ // | |
+ // | |
+ // LL | | foo(tx.clone());
+ // LL | | }).await;
+ // | | - ^^^^^^ await occurs here, with value maybe used later
+ // | |__________|
+ // | has type `closure` which is not `Send`
+ // note: value is later dropped here
+ // LL | | }).await;
+ // | | ^
+ //
+ span.push_span_label(
+ yield_span,
+ format!("{} occurs here, with {} maybe used later", await_or_yield, snippet),
+ );
+ span.push_span_label(
+ interior_span,
+ format!("has type `{}` which {}", target_ty, trait_explanation),
+ );
+ // If available, use the scope span to annotate the drop location.
+ let mut scope_note = None;
+ if let Some(scope_span) = scope_span {
+ let scope_span = source_map.end_point(scope_span);
+
+ let msg = format!("{} is later dropped here", snippet);
+ if source_map.is_multiline(yield_span.between(scope_span)) {
+ span.push_span_label(scope_span, msg);
+ } else {
+ scope_note = Some((scope_span, msg));
+ }
+ }
+ err.span_note(
+ span,
+ &format!(
+ "{} {} as this value is used across {}",
+ future_or_generator, trait_explanation, an_await_or_yield
+ ),
+ );
+ if let Some((span, msg)) = scope_note {
+ err.span_note(span, &msg);
+ }
+ }
+ };
+ match interior_or_upvar_span {
+ GeneratorInteriorOrUpvar::Interior(interior_span) => {
+ if let Some((scope_span, yield_span, expr, 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.
+ let mut span = MultiSpan::from_span(await_span);
+ span.push_span_label(
+ await_span,
+ format!(
+ "await occurs here on type `{}`, which {}",
+ target_ty, trait_explanation
+ ),
+ );
+ err.span_note(
+ span,
+ &format!(
+ "future {not_trait} as it awaits another future which {not_trait}",
+ not_trait = trait_explanation
+ ),
+ );
+ } else {
+ // Look at the last interior type to get a span for the `.await`.
+ debug!(
+ generator_interior_types = ?format_args!(
+ "{:#?}", typeck_results.as_ref().map(|t| &t.generator_interior_types)
+ ),
+ );
+ explain_yield(interior_span, yield_span, scope_span);
+ }
+
+ if let Some(expr_id) = expr {
+ let expr = hir.expect_expr(expr_id);
+ debug!("target_ty evaluated from {:?}", expr);
+
+ let parent = hir.get_parent_node(expr_id);
+ if let Some(hir::Node::Expr(e)) = hir.find(parent) {
+ let parent_span = hir.span(parent);
+ let parent_did = parent.owner.to_def_id();
+ // ```rust
+ // impl T {
+ // fn foo(&self) -> i32 {}
+ // }
+ // T.foo();
+ // ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
+ // ```
+ //
+ let is_region_borrow = if let Some(typeck_results) = typeck_results {
+ typeck_results
+ .expr_adjustments(expr)
+ .iter()
+ .any(|adj| adj.is_region_borrow())
+ } else {
+ false
+ };
+
+ // ```rust
+ // struct Foo(*const u8);
+ // bar(Foo(std::ptr::null())).await;
+ // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor.
+ // ```
+ debug!(parent_def_kind = ?self.tcx.def_kind(parent_did));
+ let is_raw_borrow_inside_fn_like_call =
+ match self.tcx.def_kind(parent_did) {
+ DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
+ _ => false,
+ };
+ if let Some(typeck_results) = typeck_results {
+ if (typeck_results.is_method_call(e) && is_region_borrow)
+ || is_raw_borrow_inside_fn_like_call
+ {
+ err.span_help(
+ parent_span,
+ "consider moving this into a `let` \
+ binding to create a shorter lived borrow",
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ GeneratorInteriorOrUpvar::Upvar(upvar_span) => {
+ // `Some(ref_ty)` if `target_ty` is `&T` and `T` fails to impl `Sync`
+ let refers_to_non_sync = match target_ty.kind() {
+ ty::Ref(_, ref_ty, _) => match self.evaluate_obligation(&obligation) {
+ Ok(eval) if !eval.may_apply() => Some(ref_ty),
+ _ => None,
+ },
+ _ => None,
+ };
+
+ let (span_label, span_note) = match refers_to_non_sync {
+ // if `target_ty` is `&T` and `T` fails to impl `Sync`,
+ // include suggestions to make `T: Sync` so that `&T: Send`
+ Some(ref_ty) => (
+ format!(
+ "has type `{}` which {}, because `{}` is not `Sync`",
+ target_ty, trait_explanation, ref_ty
+ ),
+ format!(
+ "captured value {} because `&` references cannot be sent unless their referent is `Sync`",
+ trait_explanation
+ ),
+ ),
+ None => (
+ format!("has type `{}` which {}", target_ty, trait_explanation),
+ format!("captured value {}", trait_explanation),
+ ),
+ };
+
+ let mut span = MultiSpan::from_span(upvar_span);
+ span.push_span_label(upvar_span, span_label);
+ err.span_note(span, &span_note);
+ }
+ }
+
+ // Add a note for the item obligation that remains - normally a note pointing to the
+ // bound that introduced the obligation (e.g. `T: Send`).
+ debug!(?next_code);
+ self.note_obligation_cause_code(
+ err,
+ &obligation.predicate,
+ obligation.param_env,
+ next_code.unwrap(),
+ &mut Vec::new(),
+ &mut Default::default(),
+ );
+ }
+
+ fn note_obligation_cause_code<T>(
+ &self,
+ err: &mut Diagnostic,
+ predicate: &T,
+ param_env: ty::ParamEnv<'tcx>,
+ cause_code: &ObligationCauseCode<'tcx>,
+ obligated_types: &mut Vec<Ty<'tcx>>,
+ seen_requirements: &mut FxHashSet<DefId>,
+ ) where
+ T: fmt::Display,
+ {
+ let tcx = self.tcx;
+ match *cause_code {
+ ObligationCauseCode::ExprAssignable
+ | ObligationCauseCode::MatchExpressionArm { .. }
+ | ObligationCauseCode::Pattern { .. }
+ | ObligationCauseCode::IfExpression { .. }
+ | ObligationCauseCode::IfExpressionWithNoElse
+ | ObligationCauseCode::MainFunctionType
+ | ObligationCauseCode::StartFunctionType
+ | ObligationCauseCode::IntrinsicType
+ | ObligationCauseCode::MethodReceiver
+ | ObligationCauseCode::ReturnNoExpression
+ | ObligationCauseCode::UnifyReceiver(..)
+ | ObligationCauseCode::OpaqueType
+ | ObligationCauseCode::MiscObligation
+ | ObligationCauseCode::WellFormed(..)
+ | ObligationCauseCode::MatchImpl(..)
+ | ObligationCauseCode::ReturnType
+ | ObligationCauseCode::ReturnValue(_)
+ | ObligationCauseCode::BlockTailExpression(_)
+ | ObligationCauseCode::AwaitableExpr(_)
+ | ObligationCauseCode::ForLoopIterator
+ | ObligationCauseCode::QuestionMark
+ | ObligationCauseCode::CheckAssociatedTypeBounds { .. }
+ | ObligationCauseCode::LetElse
+ | ObligationCauseCode::BinOp { .. } => {}
+ ObligationCauseCode::SliceOrArrayElem => {
+ err.note("slice and array elements must have `Sized` type");
+ }
+ ObligationCauseCode::TupleElem => {
+ err.note("only the last element of a tuple may have a dynamically sized type");
+ }
+ ObligationCauseCode::ProjectionWf(data) => {
+ err.note(&format!("required so that the projection `{}` is well-formed", data,));
+ }
+ ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
+ err.note(&format!(
+ "required so that reference `{}` does not outlive its referent",
+ ref_ty,
+ ));
+ }
+ ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
+ err.note(&format!(
+ "required so that the lifetime bound of `{}` for `{}` is satisfied",
+ region, object_ty,
+ ));
+ }
+ ObligationCauseCode::ItemObligation(_item_def_id) => {
+ // We hold the `DefId` of the item introducing the obligation, but displaying it
+ // doesn't add user usable information. It always point at an associated item.
+ }
+ ObligationCauseCode::BindingObligation(item_def_id, span) => {
+ let item_name = tcx.def_path_str(item_def_id);
+ let mut multispan = MultiSpan::from(span);
+ if let Some(ident) = tcx.opt_item_ident(item_def_id) {
+ let sm = tcx.sess.source_map();
+ let same_line =
+ match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) {
+ (Ok(l), Ok(r)) => l.line == r.line,
+ _ => true,
+ };
+ if !ident.span.overlaps(span) && !same_line {
+ multispan.push_span_label(ident.span, "required by a bound in this");
+ }
+ }
+ let descr = format!("required by a bound in `{}`", item_name);
+ if span != DUMMY_SP {
+ let msg = format!("required by this bound in `{}`", item_name);
+ multispan.push_span_label(span, msg);
+ err.span_note(multispan, &descr);
+ } else {
+ err.span_note(tcx.def_span(item_def_id), &descr);
+ }
+ }
+ ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => {
+ err.note(&format!(
+ "required for the cast from `{}` to the object type `{}`",
+ self.ty_to_string(concrete_ty),
+ self.ty_to_string(object_ty)
+ ));
+ }
+ ObligationCauseCode::Coercion { source: _, target } => {
+ err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
+ }
+ ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
+ err.note(
+ "the `Copy` trait is required because this value will be copied for each element of the array",
+ );
+
+ 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];`",
+ );
+ }
+
+ if self.tcx.sess.is_nightly_build() && is_const_fn {
+ err.help(
+ "create an inline `const` block, see RFC #2920 \
+ <https://github.com/rust-lang/rfcs/pull/2920> for more information",
+ );
+ }
+ }
+ ObligationCauseCode::VariableType(hir_id) => {
+ let parent_node = self.tcx.hir().get_parent_node(hir_id);
+ match self.tcx.hir().find(parent_node) {
+ Some(Node::Local(hir::Local {
+ init: Some(hir::Expr { kind: hir::ExprKind::Index(_, _), span, .. }),
+ ..
+ })) => {
+ // When encountering an assignment of an unsized trait, like
+ // `let x = ""[..];`, provide a suggestion to borrow the initializer in
+ // order to use have a slice instead.
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider borrowing here",
+ "&",
+ Applicability::MachineApplicable,
+ );
+ err.note("all local variables must have a statically known size");
+ }
+ Some(Node::Param(param)) => {
+ err.span_suggestion_verbose(
+ param.ty_span.shrink_to_lo(),
+ "function arguments must have a statically known size, borrowed types \
+ always have a known size",
+ "&",
+ Applicability::MachineApplicable,
+ );
+ }
+ _ => {
+ err.note("all local variables must have a statically known size");
+ }
+ }
+ if !self.tcx.features().unsized_locals {
+ err.help("unsized locals are gated as an unstable feature");
+ }
+ }
+ ObligationCauseCode::SizedArgumentType(sp) => {
+ if let Some(span) = sp {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "function arguments must have a statically known size, borrowed types \
+ always have a known size",
+ "&",
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.note("all function arguments must have a statically known size");
+ }
+ if tcx.sess.opts.unstable_features.is_nightly_build()
+ && !self.tcx.features().unsized_fn_params
+ {
+ err.help("unsized fn params are gated as an unstable feature");
+ }
+ }
+ ObligationCauseCode::SizedReturnType => {
+ 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");
+ }
+ ObligationCauseCode::SizedBoxType => {
+ err.note("the type of a box expression must have a statically known size");
+ }
+ ObligationCauseCode::AssignmentLhsSized => {
+ err.note("the left-hand-side of an assignment must have a statically known size");
+ }
+ ObligationCauseCode::TupleInitializerSized => {
+ err.note("tuples must have a statically known size to be initialized");
+ }
+ ObligationCauseCode::StructInitializerSized => {
+ err.note("structs must have a statically known size to be initialized");
+ }
+ ObligationCauseCode::FieldSized { adt_kind: ref item, last, span } => {
+ match *item {
+ AdtKind::Struct => {
+ if last {
+ err.note(
+ "the last field of a packed struct may only have a \
+ dynamically sized type if it does not need drop to be run",
+ );
+ } else {
+ err.note(
+ "only the last field of a struct may have a dynamically sized type",
+ );
+ }
+ }
+ AdtKind::Union => {
+ err.note("no field of a union may have a dynamically sized type");
+ }
+ AdtKind::Enum => {
+ err.note("no field of an enum variant may have a dynamically sized type");
+ }
+ }
+ err.help("change the field's type to have a statically known size");
+ err.span_suggestion(
+ span.shrink_to_lo(),
+ "borrowed types always have a statically known size",
+ "&",
+ Applicability::MachineApplicable,
+ );
+ err.multipart_suggestion(
+ "the `Box` type always has a statically known size and allocates its contents \
+ in the heap",
+ vec![
+ (span.shrink_to_lo(), "Box<".to_string()),
+ (span.shrink_to_hi(), ">".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ }
+ ObligationCauseCode::ConstSized => {
+ err.note("constant expressions must have a statically known size");
+ }
+ ObligationCauseCode::InlineAsmSized => {
+ err.note("all inline asm arguments must have a statically known size");
+ }
+ ObligationCauseCode::ConstPatternStructural => {
+ err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`");
+ }
+ ObligationCauseCode::SharedStatic => {
+ err.note("shared static variables must have a type that implements `Sync`");
+ }
+ ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
+ let ty = parent_trait_ref.skip_binder().self_ty();
+ if parent_trait_ref.references_error() {
+ // NOTE(eddyb) this was `.cancel()`, but `err`
+ // is borrowed, so we can't fully defuse it.
+ err.downgrade_to_delayed_bug();
+ return;
+ }
+
+ // If the obligation for a tuple is set directly by a Generator 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
+ } else {
+ if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code
+ {
+ 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::Closure(..))
+ } else {
+ false
+ }
+ };
+
+ let from_generator = tcx.lang_items().from_generator_fn().unwrap();
+
+ // Don't print the tuple of capture types
+ 'print: {
+ if !is_upvar_tys_infer_tuple {
+ let msg = format!("required because it appears within the type `{}`", ty);
+ match ty.kind() {
+ ty::Adt(def, _) => {
+ // `gen_future` is used in all async functions; it doesn't add any additional info.
+ if self.tcx.is_diagnostic_item(sym::gen_future, def.did()) {
+ break 'print;
+ }
+ match self.tcx.opt_item_ident(def.did()) {
+ Some(ident) => err.span_note(ident.span, &msg),
+ None => err.note(&msg),
+ }
+ }
+ ty::Opaque(def_id, _) => {
+ // Avoid printing the future from `core::future::from_generator`, it's not helpful
+ if tcx.parent(*def_id) == from_generator {
+ break 'print;
+ }
+
+ // If the previous type is `from_generator`, 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).
+ let is_future = tcx.ty_is_opaque_future(ty);
+ debug!(
+ ?obligated_types,
+ ?is_future,
+ "note_obligation_cause_code: check for async fn"
+ );
+ if is_future
+ && obligated_types.last().map_or(false, |ty| match ty.kind() {
+ ty::Opaque(last_def_id, _) => {
+ tcx.parent(*last_def_id) == from_generator
+ }
+ _ => false,
+ })
+ {
+ break 'print;
+ }
+ err.span_note(self.tcx.def_span(def_id), &msg)
+ }
+ ty::GeneratorWitness(bound_tys) => {
+ use std::fmt::Write;
+
+ // FIXME: this is kind of an unusual format for rustc, can we make it more clear?
+ // Maybe we should just remove this note altogether?
+ // FIXME: only print types which don't meet the trait requirement
+ let mut msg =
+ "required because it captures the following types: ".to_owned();
+ for ty in bound_tys.skip_binder() {
+ write!(msg, "`{}`, ", ty).unwrap();
+ }
+ err.note(msg.trim_end_matches(", "))
+ }
+ ty::Generator(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();
+ err.span_note(
+ sp,
+ &format!("required because it's used within this {}", kind),
+ )
+ }
+ ty::Closure(def_id, _) => err.span_note(
+ self.tcx.def_span(def_id),
+ &format!("required because it's used within this closure"),
+ ),
+ _ => err.note(&msg),
+ };
+ }
+ }
+
+ obligated_types.push(ty);
+
+ let parent_predicate = parent_trait_ref.to_predicate(tcx);
+ if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
+ // #74711: avoid a stack overflow
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ err,
+ &parent_predicate,
+ param_env,
+ &data.parent_code,
+ obligated_types,
+ seen_requirements,
+ )
+ });
+ } else {
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ err,
+ &parent_predicate,
+ param_env,
+ cause_code.peel_derives(),
+ obligated_types,
+ seen_requirements,
+ )
+ });
+ }
+ }
+ ObligationCauseCode::ImplDerivedObligation(ref data) => {
+ let mut parent_trait_pred =
+ self.resolve_vars_if_possible(data.derived.parent_trait_pred);
+ parent_trait_pred.remap_constness_diag(param_env);
+ let parent_def_id = parent_trait_pred.def_id();
+ let msg = format!(
+ "required because of the requirements on the impl of `{}` for `{}`",
+ parent_trait_pred.print_modifiers_and_trait_path(),
+ parent_trait_pred.skip_binder().self_ty()
+ );
+ let mut is_auto_trait = false;
+ match self.tcx.hir().get_if_local(data.impl_def_id) {
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(is_auto, ..),
+ ident,
+ ..
+ })) => {
+ // FIXME: we should do something else so that it works even on crate foreign
+ // auto traits.
+ is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
+ err.span_note(ident.span, &msg)
+ }
+ Some(Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+ ..
+ })) => {
+ let mut spans = Vec::with_capacity(2);
+ if let Some(trait_ref) = of_trait {
+ spans.push(trait_ref.path.span);
+ }
+ spans.push(self_ty.span);
+ err.span_note(spans, &msg)
+ }
+ _ => err.note(&msg),
+ };
+
+ let mut parent_predicate = parent_trait_pred.to_predicate(tcx);
+ let mut data = &data.derived;
+ let mut count = 0;
+ seen_requirements.insert(parent_def_id);
+ if is_auto_trait {
+ // We don't want to point at the ADT saying "required because it appears within
+ // the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`.
+ while let ObligationCauseCode::BuiltinDerivedObligation(derived) =
+ &*data.parent_code
+ {
+ let child_trait_ref =
+ self.resolve_vars_if_possible(derived.parent_trait_pred);
+ let child_def_id = child_trait_ref.def_id();
+ if seen_requirements.insert(child_def_id) {
+ break;
+ }
+ data = derived;
+ parent_predicate = child_trait_ref.to_predicate(tcx);
+ parent_trait_pred = child_trait_ref;
+ }
+ }
+ while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
+ // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
+ let child_trait_pred =
+ self.resolve_vars_if_possible(child.derived.parent_trait_pred);
+ let child_def_id = child_trait_pred.def_id();
+ if seen_requirements.insert(child_def_id) {
+ break;
+ }
+ count += 1;
+ data = &child.derived;
+ parent_predicate = child_trait_pred.to_predicate(tcx);
+ parent_trait_pred = child_trait_pred;
+ }
+ if count > 0 {
+ err.note(&format!(
+ "{} redundant requirement{} hidden",
+ count,
+ pluralize!(count)
+ ));
+ err.note(&format!(
+ "required because of the requirements on the impl of `{}` for `{}`",
+ parent_trait_pred.print_modifiers_and_trait_path(),
+ parent_trait_pred.skip_binder().self_ty()
+ ));
+ }
+ // #74711: avoid a stack overflow
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ err,
+ &parent_predicate,
+ param_env,
+ &data.parent_code,
+ obligated_types,
+ seen_requirements,
+ )
+ });
+ }
+ ObligationCauseCode::DerivedObligation(ref data) => {
+ let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
+ let parent_predicate = parent_trait_ref.to_predicate(tcx);
+ // #74711: avoid a stack overflow
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ err,
+ &parent_predicate,
+ param_env,
+ &data.parent_code,
+ obligated_types,
+ seen_requirements,
+ )
+ });
+ }
+ ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id,
+ call_hir_id,
+ ref parent_code,
+ } => {
+ let hir = self.tcx.hir();
+ if let Some(Node::Expr(expr @ hir::Expr { kind: hir::ExprKind::Block(..), .. })) =
+ hir.find(arg_hir_id)
+ {
+ let in_progress_typeck_results =
+ self.in_progress_typeck_results.map(|t| t.borrow());
+ let parent_id = hir.get_parent_item(arg_hir_id);
+ let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner == parent_id => t,
+ _ => self.tcx.typeck(parent_id),
+ };
+ let ty = typeck_results.expr_ty_adjusted(expr);
+ let span = expr.peel_blocks().span;
+ if Some(span) != err.span.primary_span() {
+ err.span_label(
+ span,
+ &if ty.references_error() {
+ String::new()
+ } else {
+ format!("this tail expression is of type `{:?}`", ty)
+ },
+ );
+ }
+ }
+ if let Some(Node::Expr(hir::Expr {
+ kind:
+ hir::ExprKind::Call(hir::Expr { span, .. }, _)
+ | hir::ExprKind::MethodCall(
+ hir::PathSegment { ident: Ident { span, .. }, .. },
+ ..,
+ ),
+ ..
+ })) = hir.find(call_hir_id)
+ {
+ if Some(*span) != err.span.primary_span() {
+ err.span_label(*span, "required by a bound introduced by this call");
+ }
+ }
+ ensure_sufficient_stack(|| {
+ self.note_obligation_cause_code(
+ err,
+ predicate,
+ param_env,
+ &parent_code,
+ obligated_types,
+ seen_requirements,
+ )
+ });
+ }
+ ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
+ let item_name = self.tcx.item_name(trait_item_def_id);
+ let msg = format!(
+ "the requirement `{}` appears on the `impl`'s {kind} `{}` but not on the \
+ corresponding trait's {kind}",
+ predicate, item_name,
+ );
+ let sp = self
+ .tcx
+ .opt_item_ident(trait_item_def_id)
+ .map(|i| i.span)
+ .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id));
+ let mut assoc_span: MultiSpan = sp.into();
+ assoc_span.push_span_label(
+ sp,
+ format!("this trait's {kind} doesn't have the requirement `{}`", predicate),
+ );
+ if let Some(ident) = self
+ .tcx
+ .opt_associated_item(trait_item_def_id)
+ .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
+ {
+ assoc_span.push_span_label(ident.span, "in this trait");
+ }
+ err.span_note(assoc_span, &msg);
+ }
+ ObligationCauseCode::TrivialBound => {
+ err.help("see issue #48214");
+ if tcx.sess.opts.unstable_features.is_nightly_build() {
+ err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable");
+ }
+ }
+ ObligationCauseCode::OpaqueReturnType(expr_info) => {
+ if let Some((expr_ty, expr_span)) = expr_info {
+ let expr_ty = self.resolve_vars_if_possible(expr_ty);
+ err.span_label(
+ expr_span,
+ format!("return type was inferred to be `{expr_ty}` here"),
+ );
+ }
+ }
+ }
+ }
+
+ 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),
+ ));
+ }
+
+ #[instrument(
+ level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty())
+ )]
+ fn suggest_await_before_try(
+ &self,
+ err: &mut Diagnostic,
+ obligation: &PredicateObligation<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ span: Span,
+ ) {
+ let body_hir_id = obligation.cause.body_id;
+ let item_id = self.tcx.hir().get_parent_node(body_hir_id);
+
+ if let Some(body_id) =
+ self.tcx.hir().maybe_body_owned_by(self.tcx.hir().local_def_id(item_id))
+ {
+ let body = self.tcx.hir().body(body_id);
+ if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+ let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
+
+ let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
+ let impls_future = self.type_implements_trait(
+ future_trait,
+ self.tcx.erase_late_bound_regions(self_ty),
+ ty::List::empty(),
+ obligation.param_env,
+ );
+ if !impls_future.must_apply_modulo_regions() {
+ return;
+ }
+
+ let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
+ // `<T as Future>::Output`
+ let projection_ty = trait_pred.map_bound(|trait_pred| {
+ self.tcx.mk_projection(
+ item_def_id,
+ // Future::Output has no substs
+ self.tcx.mk_substs_trait(trait_pred.self_ty(), &[]),
+ )
+ });
+ let projection_ty = normalize_to(
+ &mut SelectionContext::new(self),
+ obligation.param_env,
+ obligation.cause.clone(),
+ projection_ty,
+ &mut vec![],
+ );
+
+ debug!(
+ normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
+ );
+ let try_obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env,
+ trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
+ );
+ debug!(try_trait_obligation = ?try_obligation);
+ if self.predicate_may_hold(&try_obligation)
+ && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
+ && snippet.ends_with('?')
+ {
+ err.span_suggestion_verbose(
+ span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
+ "consider `await`ing on the `Future`",
+ ".await",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+
+ fn suggest_floating_point_literal(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_ref: &ty::PolyTraitRef<'tcx>,
+ ) {
+ let rhs_span = match obligation.cause.code() {
+ ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span,
+ _ => return,
+ };
+ match (
+ trait_ref.skip_binder().self_ty().kind(),
+ trait_ref.skip_binder().substs.type_at(1).kind(),
+ ) {
+ (ty::Float(_), ty::Infer(InferTy::IntVar(_))) => {
+ err.span_suggestion_verbose(
+ rhs_span.shrink_to_hi(),
+ "consider using a floating-point literal by writing it with `.0`",
+ ".0",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ }
+ }
+
+ fn suggest_derive(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) {
+ let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
+ return;
+ };
+ let (adt, substs) = match trait_pred.skip_binder().self_ty().kind() {
+ ty::Adt(adt, substs) if adt.did().is_local() => (adt, substs),
+ _ => return,
+ };
+ let can_derive = {
+ let is_derivable_trait = match diagnostic_name {
+ sym::Default => !adt.is_enum(),
+ sym::PartialEq | sym::PartialOrd => {
+ let rhs_ty = trait_pred.skip_binder().trait_ref.substs.type_at(1);
+ trait_pred.skip_binder().self_ty() == rhs_ty
+ }
+ sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
+ _ => false,
+ };
+ is_derivable_trait &&
+ // Ensure all fields impl the trait.
+ adt.all_fields().all(|field| {
+ let field_ty = field.ty(self.tcx, substs);
+ let trait_substs = match diagnostic_name {
+ sym::PartialEq | sym::PartialOrd => {
+ self.tcx.mk_substs_trait(field_ty, &[field_ty.into()])
+ }
+ _ => self.tcx.mk_substs_trait(field_ty, &[]),
+ };
+ let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ substs: trait_substs,
+ ..trait_pred.skip_binder().trait_ref
+ },
+ ..*tr
+ });
+ let field_obl = Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ trait_pred.to_predicate(self.tcx),
+ );
+ self.predicate_must_hold_modulo_regions(&field_obl)
+ })
+ };
+ if can_derive {
+ err.span_suggestion_verbose(
+ self.tcx.def_span(adt.did()).shrink_to_lo(),
+ &format!(
+ "consider annotating `{}` with `#[derive({})]`",
+ trait_pred.skip_binder().self_ty(),
+ diagnostic_name,
+ ),
+ format!("#[derive({})]\n", diagnostic_name),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
+ fn suggest_dereferencing_index(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ 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)
+ && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.substs.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",
+ '*',
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
+
+/// Collect all the returned expressions within the input expression.
+/// Used to point at the return spans when we want to suggest some change to them.
+#[derive(Default)]
+pub struct ReturnsVisitor<'v> {
+ pub returns: Vec<&'v hir::Expr<'v>>,
+ in_block_tail: bool,
+}
+
+impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ // Visit every expression to detect `return` paths, either through the function's tail
+ // expression or `return` statements. We walk all nodes to find `return` statements, but
+ // we only care about tail expressions when `in_block_tail` is `true`, which means that
+ // they're in the return path of the function body.
+ match ex.kind {
+ hir::ExprKind::Ret(Some(ex)) => {
+ self.returns.push(ex);
+ }
+ hir::ExprKind::Block(block, _) if self.in_block_tail => {
+ self.in_block_tail = false;
+ for stmt in block.stmts {
+ hir::intravisit::walk_stmt(self, stmt);
+ }
+ self.in_block_tail = true;
+ if let Some(expr) = block.expr {
+ self.visit_expr(expr);
+ }
+ }
+ hir::ExprKind::If(_, then, else_opt) if self.in_block_tail => {
+ self.visit_expr(then);
+ if let Some(el) = else_opt {
+ self.visit_expr(el);
+ }
+ }
+ hir::ExprKind::Match(_, arms, _) if self.in_block_tail => {
+ for arm in arms {
+ self.visit_expr(arm.body);
+ }
+ }
+ // We need to walk to find `return`s in the entire body.
+ _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex),
+ _ => self.returns.push(ex),
+ }
+ }
+
+ fn visit_body(&mut self, body: &'v hir::Body<'v>) {
+ assert!(!self.in_block_tail);
+ if body.generator_kind().is_none() {
+ if let hir::ExprKind::Block(block, None) = body.value.kind {
+ if block.expr.is_some() {
+ self.in_block_tail = true;
+ }
+ }
+ }
+ hir::intravisit::walk_body(self, body);
+ }
+}
+
+/// Collect all the awaited expressions within the input expression.
+#[derive(Default)]
+struct AwaitsVisitor {
+ awaits: Vec<hir::HirId>,
+}
+
+impl<'v> Visitor<'v> for AwaitsVisitor {
+ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+ if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind {
+ self.awaits.push(id)
+ }
+ hir::intravisit::walk_expr(self, ex)
+ }
+}
+
+pub trait NextTypeParamName {
+ fn next_type_param_name(&self, name: Option<&str>) -> String;
+}
+
+impl NextTypeParamName for &[hir::GenericParam<'_>] {
+ fn next_type_param_name(&self, name: Option<&str>) -> String {
+ // This is the list of possible parameter names that we might suggest.
+ let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase());
+ let name = name.as_deref();
+ let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
+ let used_names = self
+ .iter()
+ .filter_map(|p| match p.name {
+ hir::ParamName::Plain(ident) => Some(ident.name),
+ _ => None,
+ })
+ .collect::<Vec<_>>();
+
+ possible_names
+ .iter()
+ .find(|n| !used_names.contains(&Symbol::intern(n)))
+ .unwrap_or(&"ParamName")
+ .to_string()
+ }
+}
+
+fn suggest_trait_object_return_type_alternatives(
+ err: &mut Diagnostic,
+ ret_ty: Span,
+ trait_obj: &str,
+ is_object_safe: bool,
+) {
+ err.span_suggestion(
+ ret_ty,
+ "use some type `T` that is `T: Sized` as the return type if all return paths have the \
+ same type",
+ "T",
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion(
+ ret_ty,
+ &format!(
+ "use `impl {}` as the return type if all return paths have the same type but you \
+ want to expose only the trait in the signature",
+ trait_obj,
+ ),
+ format!("impl {}", trait_obj),
+ Applicability::MaybeIncorrect,
+ );
+ if is_object_safe {
+ err.multipart_suggestion(
+ &format!(
+ "use a boxed trait object if all return paths implement trait `{}`",
+ trait_obj,
+ ),
+ vec![
+ (ret_ty.shrink_to_lo(), "Box<".to_string()),
+ (ret_ty.shrink_to_hi(), ">".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+}
+
+/// Collect the spans that we see the generic param `param_did`
+struct ReplaceImplTraitVisitor<'a> {
+ ty_spans: &'a mut Vec<Span>,
+ param_did: DefId,
+}
+
+impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> {
+ fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) {
+ if let hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: hir::def::Res::Def(_, segment_did), .. },
+ )) = t.kind
+ {
+ if self.param_did == *segment_did {
+ // `fn foo(t: impl Trait)`
+ // ^^^^^^^^^^ get this to suggest `T` instead
+
+ // There might be more than one `impl Trait`.
+ self.ty_spans.push(t.span);
+ return;
+ }
+ }
+
+ hir::intravisit::walk_ty(self, t);
+ }
+}
+
+// Replace `param` with `replace_ty`
+struct ReplaceImplTraitFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param: &'tcx ty::GenericParamDef,
+ replace_ty: Ty<'tcx>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReplaceImplTraitFolder<'tcx> {
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if let ty::Param(ty::ParamTy { index, .. }) = t.kind() {
+ if self.param.index == *index {
+ return self.replace_ty;
+ }
+ }
+ t.super_fold_with(self)
+ }
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
new file mode 100644
index 000000000..556ef466c
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -0,0 +1,757 @@
+use crate::infer::{InferCtxt, TyOrConstInferVar};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::obligation_forest::ProcessResult;
+use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
+use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
+use rustc_infer::traits::ProjectionCacheKey;
+use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
+use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable};
+use std::marker::PhantomData;
+
+use super::const_evaluatable;
+use super::project::{self, ProjectAndUnifyResult};
+use super::select::SelectionContext;
+use super::wf;
+use super::CodeAmbiguity;
+use super::CodeProjectionError;
+use super::CodeSelectionError;
+use super::EvaluationResult;
+use super::Unimplemented;
+use super::{FulfillmentError, FulfillmentErrorCode};
+use super::{ObligationCause, PredicateObligation};
+
+use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::project::PolyProjectionObligation;
+use crate::traits::project::ProjectionCacheKeyExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+
+impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
+ /// Note that we include both the `ParamEnv` and the `Predicate`,
+ /// as the `ParamEnv` can influence whether fulfillment succeeds
+ /// or fails.
+ type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>;
+
+ fn as_cache_key(&self) -> Self::CacheKey {
+ self.obligation.param_env.and(self.obligation.predicate)
+ }
+}
+
+/// The fulfillment context is used to drive trait resolution. It
+/// consists of a list of obligations that must be (eventually)
+/// satisfied. The job is to track which are satisfied, which yielded
+/// errors, and which are still pending. At any point, users can call
+/// `select_where_possible`, and the fulfillment context will try to do
+/// selection, retaining only those obligations that remain
+/// ambiguous. This may be helpful in pushing type inference
+/// along. Once all type inference constraints have been generated, the
+/// method `select_all_or_error` can be used to report any remaining
+/// ambiguous cases as errors.
+pub struct FulfillmentContext<'tcx> {
+ // A list of all obligations that have been registered with this
+ // fulfillment context.
+ predicates: ObligationForest<PendingPredicateObligation<'tcx>>,
+
+ relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
+
+ // Is it OK to register obligations into this infcx inside
+ // an infcx snapshot?
+ //
+ // The "primary fulfillment" in many cases in typeck lives
+ // outside of any snapshot, so any use of it inside a snapshot
+ // will lead to trouble and therefore is checked against, but
+ // other fulfillment contexts sometimes do live inside of
+ // a snapshot (they don't *straddle* a snapshot, so there
+ // is no trouble there).
+ usable_in_snapshot: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct PendingPredicateObligation<'tcx> {
+ pub obligation: PredicateObligation<'tcx>,
+ // This is far more often read than modified, meaning that we
+ // 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>>,
+}
+
+// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+static_assert_size!(PendingPredicateObligation<'_>, 72);
+
+impl<'a, 'tcx> FulfillmentContext<'tcx> {
+ /// Creates a new fulfillment context.
+ pub fn new() -> FulfillmentContext<'tcx> {
+ FulfillmentContext {
+ predicates: ObligationForest::new(),
+ relationships: FxHashMap::default(),
+ usable_in_snapshot: false,
+ }
+ }
+
+ pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
+ FulfillmentContext {
+ predicates: ObligationForest::new(),
+ relationships: FxHashMap::default(),
+ usable_in_snapshot: true,
+ }
+ }
+
+ /// Attempts to select obligations using `selcx`.
+ fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
+ let _enter = span.enter();
+
+ // Process pending obligations.
+ let outcome: Outcome<_, _> =
+ self.predicates.process_obligations(&mut FulfillProcessor { selcx });
+
+ // FIXME: if we kept the original cache key, we could mark projection
+ // obligations as complete for the projection cache here.
+
+ let errors: Vec<FulfillmentError<'tcx>> =
+ outcome.errors.into_iter().map(to_fulfillment_error).collect();
+
+ debug!(
+ "select({} predicates remaining, {} errors) done",
+ self.predicates.len(),
+ errors.len()
+ );
+
+ errors
+ }
+}
+
+impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
+ /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
+ /// creating a fresh type variable `$0` as well as a projection
+ /// predicate `<SomeType as SomeTrait>::X == $0`. When the
+ /// inference engine runs, it will attempt to find an impl of
+ /// `SomeTrait` or a where-clause that lets us unify `$0` with
+ /// something concrete. If this fails, we'll unify `$0` with
+ /// `projection_ty` again.
+ #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))]
+ fn normalize_projection_type(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ projection_ty: ty::ProjectionTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ ) -> Ty<'tcx> {
+ debug_assert!(!projection_ty.has_escaping_bound_vars());
+
+ // FIXME(#20304) -- cache
+
+ let mut selcx = SelectionContext::new(infcx);
+ let mut obligations = vec![];
+ let normalized_ty = project::normalize_projection_type(
+ &mut selcx,
+ param_env,
+ projection_ty,
+ cause,
+ 0,
+ &mut obligations,
+ );
+ self.register_predicate_obligations(infcx, obligations);
+
+ debug!(?normalized_ty);
+
+ normalized_ty.ty().unwrap()
+ }
+
+ fn register_predicate_obligation(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ obligation: PredicateObligation<'tcx>,
+ ) {
+ // this helps to reduce duplicate errors, as well as making
+ // debug output much nicer to read and so on.
+ let obligation = infcx.resolve_vars_if_possible(obligation);
+
+ debug!(?obligation, "register_predicate_obligation");
+
+ assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
+
+ super::relationships::update(self, infcx, &obligation);
+
+ self.predicates
+ .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
+ }
+
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
+ }
+
+ fn select_where_possible(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ ) -> Vec<FulfillmentError<'tcx>> {
+ let mut selcx = SelectionContext::new(infcx);
+ self.select(&mut selcx)
+ }
+
+ fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
+ self.predicates.map_pending_obligations(|o| o.obligation.clone())
+ }
+
+ fn relationships(&mut self) -> &mut FxHashMap<ty::TyVid, ty::FoundRelationships> {
+ &mut self.relationships
+ }
+}
+
+struct FulfillProcessor<'a, 'b, 'tcx> {
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+}
+
+fn mk_pending(os: Vec<PredicateObligation<'_>>) -> Vec<PendingPredicateObligation<'_>> {
+ os.into_iter()
+ .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] })
+ .collect()
+}
+
+impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
+ type Obligation = PendingPredicateObligation<'tcx>;
+ type Error = FulfillmentErrorCode<'tcx>;
+
+ /// Identifies whether a predicate obligation needs processing.
+ ///
+ /// This is always inlined, despite its size, because it has a single
+ /// callsite and it is called *very* frequently.
+ #[inline(always)]
+ fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
+ // If we were stalled on some unresolved variables, first check whether
+ // any of them have been resolved; if not, don't bother doing more work
+ // yet.
+ match pending_obligation.stalled_on.len() {
+ // Match arms are in order of frequency, which matters because this
+ // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
+ 1 => {
+ let infer_var = pending_obligation.stalled_on[0];
+ self.selcx.infcx().ty_or_const_infer_var_changed(infer_var)
+ }
+ 0 => {
+ // In this case we haven't changed, but wish to make a change.
+ true
+ }
+ _ => {
+ // This `for` loop was once a call to `all()`, but this lower-level
+ // form was a perf win. See #64545 for details.
+ (|| {
+ for &infer_var in &pending_obligation.stalled_on {
+ if self.selcx.infcx().ty_or_const_infer_var_changed(infer_var) {
+ return true;
+ }
+ }
+ false
+ })()
+ }
+ }
+ }
+
+ /// Processes a predicate obligation and returns either:
+ /// - `Changed(v)` if the predicate is true, presuming that `v` are also true
+ /// - `Unchanged` if we don't have enough info to be sure
+ /// - `Error(e)` if the predicate does not hold
+ ///
+ /// This is called much less often than `needs_process_obligation`, so we
+ /// never inline it.
+ #[inline(never)]
+ #[instrument(level = "debug", skip(self, pending_obligation))]
+ fn process_obligation(
+ &mut self,
+ pending_obligation: &mut PendingPredicateObligation<'tcx>,
+ ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+ pending_obligation.stalled_on.truncate(0);
+
+ let obligation = &mut pending_obligation.obligation;
+
+ debug!(?obligation, "pre-resolve");
+
+ if obligation.predicate.has_infer_types_or_consts() {
+ obligation.predicate =
+ self.selcx.infcx().resolve_vars_if_possible(obligation.predicate);
+ }
+
+ let obligation = &pending_obligation.obligation;
+
+ let infcx = self.selcx.infcx();
+
+ if obligation.predicate.has_projections() {
+ let mut obligations = Vec::new();
+ let predicate = crate::traits::project::try_normalize_with_depth_to(
+ self.selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.predicate,
+ &mut obligations,
+ );
+ if predicate != obligation.predicate {
+ obligations.push(obligation.with(predicate));
+ return ProcessResult::Changed(mk_pending(obligations));
+ }
+ }
+ let binder = obligation.predicate.kind();
+ match binder.no_bound_vars() {
+ None => match binder.skip_binder() {
+ // Evaluation will discard candidates using the leak check.
+ // This means we need to pass it the bound version of our
+ // predicate.
+ ty::PredicateKind::Trait(trait_ref) => {
+ let trait_obligation = obligation.with(binder.rebind(trait_ref));
+
+ self.process_trait_obligation(
+ obligation,
+ trait_obligation,
+ &mut pending_obligation.stalled_on,
+ )
+ }
+ ty::PredicateKind::Projection(data) => {
+ let project_obligation = obligation.with(binder.rebind(data));
+
+ self.process_projection_obligation(
+ obligation,
+ project_obligation,
+ &mut pending_obligation.stalled_on,
+ )
+ }
+ ty::PredicateKind::RegionOutlives(_)
+ | ty::PredicateKind::TypeOutlives(_)
+ | ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::Coerce(_)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..) => {
+ let pred =
+ ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
+ ProcessResult::Changed(mk_pending(vec![
+ obligation.with(pred.to_predicate(self.selcx.tcx())),
+ ]))
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for Chalk")
+ }
+ },
+ Some(pred) => match pred {
+ ty::PredicateKind::Trait(data) => {
+ let trait_obligation = obligation.with(Binder::dummy(data));
+
+ self.process_trait_obligation(
+ obligation,
+ trait_obligation,
+ &mut pending_obligation.stalled_on,
+ )
+ }
+
+ ty::PredicateKind::RegionOutlives(data) => {
+ if infcx.considering_regions || data.has_placeholders() {
+ infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
+ }
+
+ ProcessResult::Changed(vec![])
+ }
+
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
+ if infcx.considering_regions {
+ infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
+ }
+ ProcessResult::Changed(vec![])
+ }
+
+ ty::PredicateKind::Projection(ref data) => {
+ let project_obligation = obligation.with(Binder::dummy(*data));
+
+ self.process_projection_obligation(
+ obligation,
+ project_obligation,
+ &mut pending_obligation.stalled_on,
+ )
+ }
+
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ if !self.selcx.tcx().is_object_safe(trait_def_id) {
+ ProcessResult::Error(CodeSelectionError(Unimplemented))
+ } else {
+ ProcessResult::Changed(vec![])
+ }
+ }
+
+ ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
+ match self.selcx.infcx().closure_kind(closure_substs) {
+ Some(closure_kind) => {
+ if closure_kind.extends(kind) {
+ ProcessResult::Changed(vec![])
+ } else {
+ ProcessResult::Error(CodeSelectionError(Unimplemented))
+ }
+ }
+ None => ProcessResult::Unchanged,
+ }
+ }
+
+ ty::PredicateKind::WellFormed(arg) => {
+ match wf::obligations(
+ self.selcx.infcx(),
+ obligation.param_env,
+ obligation.cause.body_id,
+ obligation.recursion_depth + 1,
+ arg,
+ obligation.cause.span,
+ ) {
+ None => {
+ pending_obligation.stalled_on =
+ vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()];
+ ProcessResult::Unchanged
+ }
+ Some(os) => ProcessResult::Changed(mk_pending(os)),
+ }
+ }
+
+ ty::PredicateKind::Subtype(subtype) => {
+ match self.selcx.infcx().subtype_predicate(
+ &obligation.cause,
+ obligation.param_env,
+ Binder::dummy(subtype),
+ ) {
+ None => {
+ // None means that both are unresolved.
+ pending_obligation.stalled_on = vec![
+ TyOrConstInferVar::maybe_from_ty(subtype.a).unwrap(),
+ TyOrConstInferVar::maybe_from_ty(subtype.b).unwrap(),
+ ];
+ ProcessResult::Unchanged
+ }
+ Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+ Some(Err(err)) => {
+ let expected_found =
+ ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
+ ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
+ expected_found,
+ err,
+ ))
+ }
+ }
+ }
+
+ ty::PredicateKind::Coerce(coerce) => {
+ match self.selcx.infcx().coerce_predicate(
+ &obligation.cause,
+ obligation.param_env,
+ Binder::dummy(coerce),
+ ) {
+ None => {
+ // None means that both are unresolved.
+ pending_obligation.stalled_on = vec![
+ TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(),
+ TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(),
+ ];
+ ProcessResult::Unchanged
+ }
+ Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+ Some(Err(err)) => {
+ let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
+ ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
+ expected_found,
+ err,
+ ))
+ }
+ }
+ }
+
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ match const_evaluatable::is_const_evaluatable(
+ self.selcx.infcx(),
+ uv,
+ obligation.param_env,
+ obligation.cause.span,
+ ) {
+ Ok(()) => ProcessResult::Changed(vec![]),
+ Err(NotConstEvaluatable::MentionsInfer) => {
+ pending_obligation.stalled_on.clear();
+ pending_obligation.stalled_on.extend(
+ uv.substs
+ .iter()
+ .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+ );
+ ProcessResult::Unchanged
+ }
+ Err(
+ e @ NotConstEvaluatable::MentionsParam
+ | e @ NotConstEvaluatable::Error(_),
+ ) => ProcessResult::Error(CodeSelectionError(
+ SelectionError::NotConstEvaluatable(e),
+ )),
+ }
+ }
+
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ debug!(?c1, ?c2, "equating consts");
+ let tcx = self.selcx.tcx();
+ if tcx.features().generic_const_exprs {
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+ (c1.kind(), c2.kind())
+ {
+ if infcx.try_unify_abstract_consts(
+ a.shrink(),
+ b.shrink(),
+ obligation.param_env,
+ ) {
+ return ProcessResult::Changed(vec![]);
+ }
+ }
+ }
+
+ let stalled_on = &mut pending_obligation.stalled_on;
+
+ let mut evaluate = |c: Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+ match self.selcx.infcx().try_const_eval_resolve(
+ obligation.param_env,
+ unevaluated,
+ c.ty(),
+ Some(obligation.cause.span),
+ ) {
+ Ok(val) => Ok(val),
+ Err(e) => match e {
+ ErrorHandled::TooGeneric => {
+ stalled_on.extend(
+ unevaluated.substs.iter().filter_map(
+ TyOrConstInferVar::maybe_from_generic_arg,
+ ),
+ );
+ Err(ErrorHandled::TooGeneric)
+ }
+ _ => Err(e),
+ },
+ }
+ } else {
+ Ok(c)
+ }
+ };
+
+ match (evaluate(c1), evaluate(c2)) {
+ (Ok(c1), Ok(c2)) => {
+ match self
+ .selcx
+ .infcx()
+ .at(&obligation.cause, obligation.param_env)
+ .eq(c1, c2)
+ {
+ Ok(_) => ProcessResult::Changed(vec![]),
+ Err(err) => ProcessResult::Error(
+ FulfillmentErrorCode::CodeConstEquateError(
+ ExpectedFound::new(true, c1, c2),
+ err,
+ ),
+ ),
+ }
+ }
+ (Err(ErrorHandled::Reported(reported)), _)
+ | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error(
+ CodeSelectionError(SelectionError::NotConstEvaluatable(
+ NotConstEvaluatable::Error(reported),
+ )),
+ ),
+ (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
+ span_bug!(
+ obligation.cause.span(),
+ "ConstEquate: const_eval_resolve returned an unexpected error"
+ )
+ }
+ (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+ if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ ProcessResult::Unchanged
+ } else {
+ // Two different constants using generic parameters ~> error.
+ let expected_found = ExpectedFound::new(true, c1, c2);
+ ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+ expected_found,
+ TypeError::ConstMismatch(expected_found),
+ ))
+ }
+ }
+ }
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for Chalk")
+ }
+ },
+ }
+ }
+
+ fn process_backedge<'c, I>(
+ &mut self,
+ cycle: I,
+ _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>,
+ ) where
+ I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>,
+ {
+ if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
+ debug!("process_child_obligations: coinductive match");
+ } else {
+ let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
+ self.selcx.infcx().report_overflow_error_cycle(&cycle);
+ }
+ }
+}
+
+impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
+ #[instrument(level = "debug", skip(self, obligation, stalled_on))]
+ fn process_trait_obligation(
+ &mut self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_obligation: TraitObligation<'tcx>,
+ stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+ ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+ let infcx = self.selcx.infcx();
+ if obligation.predicate.is_global() {
+ // no type variables present, can use evaluation for better caching.
+ // FIXME: consider caching errors too.
+ if infcx.predicate_must_hold_considering_regions(obligation) {
+ debug!(
+ "selecting trait at depth {} evaluated to holds",
+ obligation.recursion_depth
+ );
+ return ProcessResult::Changed(vec![]);
+ }
+ }
+
+ match self.selcx.select(&trait_obligation) {
+ Ok(Some(impl_source)) => {
+ debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth);
+ ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
+ }
+ Ok(None) => {
+ debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth);
+
+ // This is a bit subtle: for the most part, the
+ // only reason we can fail to make progress on
+ // trait selection is because we don't have enough
+ // information about the types in the trait.
+ stalled_on.clear();
+ stalled_on.extend(substs_infer_vars(
+ self.selcx,
+ trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
+ ));
+
+ debug!(
+ "process_predicate: pending obligation {:?} now stalled on {:?}",
+ infcx.resolve_vars_if_possible(obligation.clone()),
+ stalled_on
+ );
+
+ ProcessResult::Unchanged
+ }
+ Err(selection_err) => {
+ debug!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
+
+ ProcessResult::Error(CodeSelectionError(selection_err))
+ }
+ }
+ }
+
+ fn process_projection_obligation(
+ &mut self,
+ obligation: &PredicateObligation<'tcx>,
+ project_obligation: PolyProjectionObligation<'tcx>,
+ stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+ ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+ let tcx = self.selcx.tcx();
+
+ if obligation.predicate.is_global() {
+ // no type variables present, can use evaluation for better caching.
+ // FIXME: consider caching errors too.
+ if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
+ if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(
+ &mut self.selcx,
+ project_obligation.predicate,
+ ) {
+ // If `predicate_must_hold_considering_regions` succeeds, then we've
+ // evaluated all sub-obligations. We can therefore mark the 'root'
+ // obligation as complete, and skip evaluating sub-obligations.
+ self.selcx
+ .infcx()
+ .inner
+ .borrow_mut()
+ .projection_cache()
+ .complete(key, EvaluationResult::EvaluatedToOk);
+ }
+ return ProcessResult::Changed(vec![]);
+ } else {
+ debug!("Does NOT hold: {:?}", obligation);
+ }
+ }
+
+ match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
+ ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
+ ProjectAndUnifyResult::FailedNormalization => {
+ stalled_on.clear();
+ stalled_on.extend(substs_infer_vars(
+ self.selcx,
+ project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
+ ));
+ ProcessResult::Unchanged
+ }
+ // Let the caller handle the recursion
+ ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![
+ project_obligation.with(project_obligation.predicate.to_predicate(tcx)),
+ ])),
+ ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
+ ProcessResult::Error(CodeProjectionError(e))
+ }
+ }
+ }
+}
+
+/// Returns the set of inference variables contained in `substs`.
+fn substs_infer_vars<'a, 'tcx>(
+ selcx: &mut SelectionContext<'a, 'tcx>,
+ substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
+) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
+ selcx
+ .infcx()
+ .resolve_vars_if_possible(substs)
+ .skip_binder() // ok because this check doesn't care about regions
+ .iter()
+ .filter(|arg| arg.has_infer_types_or_consts())
+ .flat_map(|arg| {
+ let mut walker = arg.walk();
+ while let Some(c) = walker.next() {
+ if !c.has_infer_types_or_consts() {
+ walker.visited.remove(&c);
+ walker.skip_current_subtree();
+ }
+ }
+ walker.visited.into_iter()
+ })
+ .filter_map(TyOrConstInferVar::maybe_from_generic_arg)
+}
+
+fn to_fulfillment_error<'tcx>(
+ error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>,
+) -> FulfillmentError<'tcx> {
+ let mut iter = error.backtrace.into_iter();
+ let obligation = iter.next().unwrap().obligation;
+ // The root obligation is the last item in the backtrace - if there's only
+ // one item, then it's the same as the main obligation
+ let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation);
+ FulfillmentError::new(obligation, error.error, root_obligation)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
new file mode 100644
index 000000000..dd2769c71
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -0,0 +1,88 @@
+//! Miscellaneous type-system utilities that are too small to deserve their own modules.
+
+use crate::infer::InferCtxtExt as _;
+use crate::traits::{self, ObligationCause};
+
+use rustc_hir as hir;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
+
+use crate::traits::error_reporting::InferCtxtExt;
+
+#[derive(Clone)]
+pub enum CopyImplementationError<'tcx> {
+ InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>)>),
+ NotAnAdt,
+ HasDestructor,
+}
+
+pub fn can_type_implement_copy<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ self_type: Ty<'tcx>,
+ parent_cause: ObligationCause<'tcx>,
+) -> Result<(), CopyImplementationError<'tcx>> {
+ // FIXME: (@jroesch) float this code up
+ tcx.infer_ctxt().enter(|infcx| {
+ let (adt, substs) = match self_type.kind() {
+ // These types used to have a builtin impl.
+ // Now libcore provides that impl.
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::Char
+ | ty::RawPtr(..)
+ | ty::Never
+ | ty::Ref(_, _, hir::Mutability::Not)
+ | ty::Array(..) => return Ok(()),
+
+ ty::Adt(adt, substs) => (adt, substs),
+
+ _ => return Err(CopyImplementationError::NotAnAdt),
+ };
+
+ let mut infringing = Vec::new();
+ for variant in adt.variants() {
+ for field in &variant.fields {
+ let ty = field.ty(tcx, substs);
+ if ty.references_error() {
+ continue;
+ }
+ let span = tcx.def_span(field.did);
+ // FIXME(compiler-errors): This gives us better spans for bad
+ // projection types like in issue-50480.
+ // If the ADT has substs, point to the cause we are given.
+ // If it does not, then this field probably doesn't normalize
+ // to begin with, and point to the bad field's span instead.
+ let cause = if field
+ .ty(tcx, traits::InternalSubsts::identity_for_item(tcx, adt.did()))
+ .has_param_types_or_consts()
+ {
+ parent_cause.clone()
+ } else {
+ ObligationCause::dummy_with_span(span)
+ };
+ let ctx = traits::FulfillmentContext::new();
+ match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
+ Ok(ty) => {
+ if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
+ infringing.push((field, ty));
+ }
+ }
+ Err(errors) => {
+ infcx.report_fulfillment_errors(&errors, None, false);
+ }
+ };
+ }
+ }
+ if !infringing.is_empty() {
+ return Err(CopyImplementationError::InfrigingFields(infringing));
+ }
+ if adt.has_dtor(tcx) {
+ return Err(CopyImplementationError::HasDestructor);
+ }
+
+ Ok(())
+ })
+}
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
new file mode 100644
index 000000000..9c6bb0731
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -0,0 +1,863 @@
+//! Trait Resolution. See the [rustc dev guide] for more information on how this works.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
+
+pub mod auto_trait;
+mod chalk_fulfill;
+pub mod codegen;
+mod coherence;
+pub mod const_evaluatable;
+mod engine;
+pub mod error_reporting;
+mod fulfill;
+pub mod misc;
+mod object_safety;
+mod on_unimplemented;
+mod project;
+pub mod query;
+pub(crate) mod relationships;
+mod select;
+mod specialize;
+mod structural_match;
+mod util;
+pub mod wf;
+
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::{InferCtxt, TyCtxtInferExt};
+use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
+use rustc_span::{sym, Span};
+use smallvec::SmallVec;
+
+use std::fmt::Debug;
+use std::ops::ControlFlow;
+
+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::ObjectSafetyViolation;
+pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
+pub use self::project::{normalize, normalize_projection_type, normalize_to};
+pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
+pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
+pub use self::specialize::specialization_graph::FutureCompatOverlapError;
+pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
+pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
+pub use self::structural_match::{
+ search_for_adt_const_param_violation, search_for_structural_match_violation,
+};
+pub use self::util::{
+ elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span,
+ elaborate_trait_ref, elaborate_trait_refs,
+};
+pub use self::util::{expand_trait_aliases, TraitAliasExpander};
+pub use self::util::{
+ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
+};
+pub use self::util::{
+ supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
+ SupertraitDefIds, Supertraits,
+};
+
+pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
+
+pub use rustc_infer::traits::*;
+
+/// Whether to skip the leak check, as part of a future compatibility warning step.
+///
+/// The "default" for skip-leak-check corresponds to the current
+/// behavior (do not skip the leak check) -- not the behavior we are
+/// transitioning into.
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
+pub enum SkipLeakCheck {
+ Yes,
+ #[default]
+ No,
+}
+
+impl SkipLeakCheck {
+ fn is_yes(self) -> bool {
+ self == SkipLeakCheck::Yes
+ }
+}
+
+/// The mode that trait queries run in.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum TraitQueryMode {
+ /// Standard/un-canonicalized queries get accurate
+ /// spans etc. passed in and hence can do reasonable
+ /// error reporting on their own.
+ Standard,
+ /// Canonicalized queries get dummy spans and hence
+ /// must generally propagate errors to
+ /// pre-canonicalization callsites.
+ Canonical,
+}
+
+/// Creates predicate obligations from the generic bounds.
+pub fn predicates_for_generics<'tcx>(
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ generic_bounds: ty::InstantiatedPredicates<'tcx>,
+) -> impl Iterator<Item = PredicateObligation<'tcx>> {
+ util::predicates_for_generics(cause, 0, param_env, generic_bounds)
+}
+
+/// Determines whether the type `ty` is known to meet `bound` and
+/// returns true if so. Returns false if `ty` either does not meet
+/// `bound` or is not known to meet bound (note that this is
+/// conservative towards *no impl*, which is the opposite of the
+/// `evaluate` methods).
+pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ def_id: DefId,
+ span: Span,
+) -> bool {
+ debug!(
+ "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
+ ty,
+ infcx.tcx.def_path_str(def_id)
+ );
+
+ let trait_ref =
+ ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) });
+ let obligation = Obligation {
+ param_env,
+ cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
+ recursion_depth: 0,
+ predicate: trait_ref.without_const().to_predicate(infcx.tcx),
+ };
+
+ let result = infcx.predicate_must_hold_modulo_regions(&obligation);
+ debug!(
+ "type_known_to_meet_ty={:?} bound={} => {:?}",
+ ty,
+ infcx.tcx.def_path_str(def_id),
+ result
+ );
+
+ if result && ty.has_infer_types_or_consts() {
+ // Because of inference "guessing", selection can sometimes claim
+ // to succeed while the success requires a guess. To ensure
+ // this function's result remains infallible, we must confirm
+ // that guess. While imperfect, I believe this is sound.
+
+ // The handling of regions in this area of the code is terrible,
+ // see issue #29149. We should be able to improve on this with
+ // NLL.
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+ // We can use a dummy node-id here because we won't pay any mind
+ // to region obligations that arise (there shouldn't really be any
+ // anyhow).
+ let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
+
+ fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
+
+ // Note: we only assume something is `Copy` if we can
+ // *definitively* show that it implements `Copy`. Otherwise,
+ // assume it is move; linear is always ok.
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
+ debug!(
+ "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
+ ty,
+ infcx.tcx.def_path_str(def_id)
+ );
+ true
+ }
+ errors => {
+ debug!(
+ ?ty,
+ bound = %infcx.tcx.def_path_str(def_id),
+ ?errors,
+ "type_known_to_meet_bound_modulo_regions"
+ );
+ false
+ }
+ }
+ } else {
+ result
+ }
+}
+
+#[instrument(level = "debug", skip(tcx, elaborated_env))]
+fn do_normalize_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ cause: ObligationCause<'tcx>,
+ elaborated_env: ty::ParamEnv<'tcx>,
+ predicates: Vec<ty::Predicate<'tcx>>,
+) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> {
+ let span = cause.span;
+ // FIXME. We should really... do something with these region
+ // obligations. But this call just continues the older
+ // behavior (i.e., doesn't cause any new bugs), and it would
+ // take some further refactoring to actually solve them. In
+ // particular, we would have to handle implied bounds
+ // properly, and that code is currently largely confined to
+ // regionck (though I made some efforts to extract it
+ // out). -nmatsakis
+ //
+ // @arielby: In any case, these obligations are checked
+ // by wfcheck anyway, so I'm not sure we have to check
+ // them here too, and we will remove this function when
+ // we move over to lazy normalization *anyway*.
+ tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
+ let fulfill_cx = FulfillmentContext::new();
+ let predicates =
+ match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
+ Ok(predicates) => predicates,
+ Err(errors) => {
+ let reported = infcx.report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
+ };
+
+ debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
+
+ // We can use the `elaborated_env` here; the region code only
+ // cares about declarations like `'a: 'b`.
+ let outlives_env = OutlivesEnvironment::new(elaborated_env);
+
+ // FIXME: It's very weird that we ignore region obligations but apparently
+ // still need to use `resolve_regions` as we need the resolved regions in
+ // the normalized predicates.
+ let errors = infcx.resolve_regions(&outlives_env);
+ if !errors.is_empty() {
+ tcx.sess.delay_span_bug(
+ span,
+ format!(
+ "failed region resolution while normalizing {elaborated_env:?}: {errors:?}"
+ ),
+ );
+ }
+
+ match infcx.fully_resolve(predicates) {
+ Ok(predicates) => Ok(predicates),
+ Err(fixup_err) => {
+ // If we encounter a fixup error, it means that some type
+ // variable wound up unconstrained. I actually don't know
+ // if this can happen, and I certainly don't expect it to
+ // happen often, but if it did happen it probably
+ // represents a legitimate failure due to some kind of
+ // unconstrained variable.
+ //
+ // @lcnr: Let's still ICE here for now. I want a test case
+ // for that.
+ span_bug!(
+ span,
+ "inference variables in normalized parameter environment: {}",
+ fixup_err
+ );
+ }
+ }
+ })
+}
+
+// FIXME: this is gonna need to be removed ...
+/// Normalizes the parameter environment, reporting errors if they occur.
+#[instrument(level = "debug", skip(tcx))]
+pub fn normalize_param_env_or_error<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ unnormalized_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+) -> ty::ParamEnv<'tcx> {
+ // I'm not wild about reporting errors here; I'd prefer to
+ // have the errors get reported at a defined place (e.g.,
+ // during typeck). Instead I have all parameter
+ // environments, in effect, going through this function
+ // and hence potentially reporting errors. This ensures of
+ // course that we never forget to normalize (the
+ // alternative seemed like it would involve a lot of
+ // manual invocations of this fn -- and then we'd have to
+ // deal with the errors at each of those sites).
+ //
+ // In any case, in practice, typeck constructs all the
+ // parameter environments once for every fn as it goes,
+ // and errors will get reported then; so outside of type inference we
+ // can be sure that no errors should occur.
+ let mut predicates: Vec<_> =
+ util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
+ .map(|obligation| obligation.predicate)
+ .collect();
+
+ debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
+
+ let elaborated_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ unnormalized_env.reveal(),
+ unnormalized_env.constness(),
+ );
+
+ // HACK: we are trying to normalize the param-env inside *itself*. The problem is that
+ // normalization expects its param-env to be already normalized, which means we have
+ // a circularity.
+ //
+ // The way we handle this is by normalizing the param-env inside an unnormalized version
+ // of the param-env, which means that if the param-env contains unnormalized projections,
+ // we'll have some normalization failures. This is unfortunate.
+ //
+ // Lazy normalization would basically handle this by treating just the
+ // normalizing-a-trait-ref-requires-itself cycles as evaluation failures.
+ //
+ // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated
+ // types, so to make the situation less bad, we normalize all the predicates *but*
+ // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and
+ // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment.
+ //
+ // This works fairly well because trait matching does not actually care about param-env
+ // TypeOutlives predicates - these are normally used by regionck.
+ let outlives_predicates: Vec<_> = predicates
+ .drain_filter(|predicate| {
+ matches!(predicate.kind().skip_binder(), ty::PredicateKind::TypeOutlives(..))
+ })
+ .collect();
+
+ debug!(
+ "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})",
+ predicates, outlives_predicates
+ );
+ let Ok(non_outlives_predicates) = do_normalize_predicates(
+ tcx,
+ cause.clone(),
+ elaborated_env,
+ predicates,
+ ) else {
+ // An unnormalized env is better than nothing.
+ debug!("normalize_param_env_or_error: errored resolving non-outlives predicates");
+ return elaborated_env;
+ };
+
+ debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates);
+
+ // Not sure whether it is better to include the unnormalized TypeOutlives predicates
+ // here. I believe they should not matter, because we are ignoring TypeOutlives param-env
+ // predicates here anyway. Keeping them here anyway because it seems safer.
+ let outlives_env: Vec<_> =
+ non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect();
+ let outlives_env = ty::ParamEnv::new(
+ tcx.intern_predicates(&outlives_env),
+ unnormalized_env.reveal(),
+ unnormalized_env.constness(),
+ );
+ let Ok(outlives_predicates) = do_normalize_predicates(
+ tcx,
+ cause,
+ outlives_env,
+ outlives_predicates,
+ ) else {
+ // An unnormalized env is better than nothing.
+ debug!("normalize_param_env_or_error: errored resolving outlives predicates");
+ return elaborated_env;
+ };
+ debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates);
+
+ let mut predicates = non_outlives_predicates;
+ predicates.extend(outlives_predicates);
+ debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
+ ty::ParamEnv::new(
+ tcx.intern_predicates(&predicates),
+ unnormalized_env.reveal(),
+ unnormalized_env.constness(),
+ )
+}
+
+pub fn fully_normalize<'a, 'tcx, T>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ mut fulfill_cx: FulfillmentContext<'tcx>,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+) -> Result<T, Vec<FulfillmentError<'tcx>>>
+where
+ T: TypeFoldable<'tcx>,
+{
+ debug!("fully_normalize_with_fulfillcx(value={:?})", value);
+ let selcx = &mut SelectionContext::new(infcx);
+ let Normalized { value: normalized_value, obligations } =
+ project::normalize(selcx, param_env, cause, value);
+ debug!(
+ "fully_normalize: normalized_value={:?} obligations={:?}",
+ normalized_value, obligations
+ );
+ for obligation in obligations {
+ fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
+ }
+
+ debug!("fully_normalize: select_all_or_error start");
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
+ debug!("fully_normalize: select_all_or_error complete");
+ let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
+ debug!("fully_normalize: resolved_value={:?}", resolved_value);
+ Ok(resolved_value)
+}
+
+/// Normalizes the predicates and checks whether they hold in an empty environment. If this
+/// returns true, then either normalize encountered an error or one of the predicates did not
+/// hold. Used when creating vtables to check for unsatisfiable methods.
+pub fn impossible_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ predicates: Vec<ty::Predicate<'tcx>>,
+) -> bool {
+ debug!("impossible_predicates(predicates={:?})", predicates);
+
+ let result = tcx.infer_ctxt().enter(|infcx| {
+ // HACK: Set tainted by errors to gracefully exit in case of overflow.
+ infcx.set_tainted_by_errors();
+
+ let param_env = ty::ParamEnv::reveal_all();
+ let mut selcx = SelectionContext::new(&infcx);
+ let mut fulfill_cx = FulfillmentContext::new();
+ let cause = ObligationCause::dummy();
+ let Normalized { value: predicates, obligations } =
+ normalize(&mut selcx, param_env, cause.clone(), predicates);
+ for obligation in obligations {
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ for predicate in predicates {
+ let obligation = Obligation::new(cause.clone(), param_env, predicate);
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ // Clean up after ourselves
+ let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
+ !errors.is_empty()
+ });
+ debug!("impossible_predicates = {:?}", result);
+ result
+}
+
+fn subst_and_check_impossible_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (DefId, SubstsRef<'tcx>),
+) -> bool {
+ debug!("subst_and_check_impossible_predicates(key={:?})", key);
+
+ let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
+
+ // Specifically check trait fulfillment to avoid an error when trying to resolve
+ // associated items.
+ if let Some(trait_def_id) = tcx.trait_of_item(key.0) {
+ let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1);
+ predicates.push(ty::Binder::dummy(trait_ref).to_poly_trait_predicate().to_predicate(tcx));
+ }
+
+ predicates.retain(|predicate| !predicate.needs_subst());
+ let result = impossible_predicates(tcx, predicates);
+
+ debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
+ result
+}
+
+#[derive(Clone, Debug)]
+enum VtblSegment<'tcx> {
+ MetadataDSA,
+ TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
+}
+
+/// Prepare the segments for a vtable
+fn prepare_vtable_segments<'tcx, T>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
+) -> Option<T> {
+ // The following constraints holds for the final arrangement.
+ // 1. The whole virtual table of the first direct super trait is included as the
+ // the prefix. If this trait doesn't have any super traits, then this step
+ // consists of the dsa metadata.
+ // 2. Then comes the proper pointer metadata(vptr) and all own methods for all
+ // other super traits except those already included as part of the first
+ // direct super trait virtual table.
+ // 3. finally, the own methods of this trait.
+
+ // This has the advantage that trait upcasting to the first direct super trait on each level
+ // is zero cost, and to another trait includes only replacing the pointer with one level indirection,
+ // while not using too much extra memory.
+
+ // For a single inheritance relationship like this,
+ // D --> C --> B --> A
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, C, D
+
+ // For a multiple inheritance relationship like this,
+ // D --> C --> A
+ // \-> B
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, B-vptr, C, D
+
+ // For a diamond inheritance relationship like this,
+ // D --> B --> A
+ // \-> C -/
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, C, C-vptr, D
+
+ // For a more complex inheritance relationship like this:
+ // O --> G --> C --> A
+ // \ \ \-> B
+ // | |-> F --> D
+ // | \-> E
+ // |-> N --> J --> H
+ // \ \-> I
+ // |-> M --> K
+ // \-> L
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G,
+ // H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr,
+ // N, N-vptr, O
+
+ // emit dsa segment first.
+ if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) {
+ return Some(v);
+ }
+
+ let mut emit_vptr_on_new_entry = false;
+ let mut visited = util::PredicateSet::new(tcx);
+ let predicate = trait_ref.without_const().to_predicate(tcx);
+ let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
+ smallvec![(trait_ref, emit_vptr_on_new_entry, None)];
+ visited.insert(predicate);
+
+ // the main traversal loop:
+ // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes
+ // that each node is emitted after all its descendents have been emitted.
+ // so we convert the directed graph into a tree by skipping all previously visited nodes using a visited set.
+ // this is done on the fly.
+ // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it
+ // stops after it finds a node that has a next-sibling node.
+ // This next-sibling node will used as the starting point of next slice.
+
+ // Example:
+ // For a diamond inheritance relationship like this,
+ // D#1 --> B#0 --> A#0
+ // \-> C#1 -/
+
+ // Starting point 0 stack [D]
+ // Loop run #0: Stack after diving in is [D B A], A is "childless"
+ // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one.
+ // Loop run #0: Emitting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here.
+ // Loop run #0: Stack after exiting out is [D C], C is the next starting point.
+ // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted).
+ // Loop run #1: Emitting the slice [D C] (in reverse order). No one has a next-sibling node.
+ // Loop run #1: Stack after exiting out is []. Now the function exits.
+
+ loop {
+ // dive deeper into the stack, recording the path
+ 'diving_in: loop {
+ if let Some((inner_most_trait_ref, _, _)) = stack.last() {
+ let inner_most_trait_ref = *inner_most_trait_ref;
+ let mut direct_super_traits_iter = tcx
+ .super_predicates_of(inner_most_trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .filter_map(move |(pred, _)| {
+ pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
+ });
+
+ 'diving_in_skip_visited_traits: loop {
+ if let Some(next_super_trait) = direct_super_traits_iter.next() {
+ if visited.insert(next_super_trait.to_predicate(tcx)) {
+ // We're throwing away potential constness of super traits here.
+ // FIXME: handle ~const super traits
+ let next_super_trait = next_super_trait.map_bound(|t| t.trait_ref);
+ stack.push((
+ next_super_trait,
+ emit_vptr_on_new_entry,
+ Some(direct_super_traits_iter),
+ ));
+ break 'diving_in_skip_visited_traits;
+ } else {
+ continue 'diving_in_skip_visited_traits;
+ }
+ } else {
+ break 'diving_in;
+ }
+ }
+ }
+ }
+
+ // Other than the left-most path, vptr should be emitted for each trait.
+ emit_vptr_on_new_entry = true;
+
+ // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
+ 'exiting_out: loop {
+ if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() {
+ if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries {
+ trait_ref: *inner_most_trait_ref,
+ emit_vptr: *emit_vptr,
+ }) {
+ return Some(v);
+ }
+
+ 'exiting_out_skip_visited_traits: loop {
+ if let Some(siblings) = siblings_opt {
+ if let Some(next_inner_most_trait_ref) = siblings.next() {
+ if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
+ // We're throwing away potential constness of super traits here.
+ // FIXME: handle ~const super traits
+ let next_inner_most_trait_ref =
+ next_inner_most_trait_ref.map_bound(|t| t.trait_ref);
+ *inner_most_trait_ref = next_inner_most_trait_ref;
+ *emit_vptr = emit_vptr_on_new_entry;
+ break 'exiting_out;
+ } else {
+ continue 'exiting_out_skip_visited_traits;
+ }
+ }
+ }
+ stack.pop();
+ continue 'exiting_out;
+ }
+ }
+ // all done
+ return None;
+ }
+ }
+}
+
+fn dump_vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ sp: Span,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ entries: &[VtblEntry<'tcx>],
+) {
+ let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries);
+ tcx.sess.struct_span_err(sp, &msg).emit();
+}
+
+fn own_existential_vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+) -> &'tcx [DefId] {
+ let trait_methods = tcx
+ .associated_items(trait_ref.def_id())
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Fn);
+ // Now list each method's DefId (for within its trait).
+ let own_entries = trait_methods.filter_map(move |trait_method| {
+ debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
+ let def_id = trait_method.def_id;
+
+ // Some methods cannot be called on an object; skip those.
+ if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+ debug!("own_existential_vtable_entry: not vtable safe");
+ return None;
+ }
+
+ Some(def_id)
+ });
+
+ tcx.arena.alloc_from_iter(own_entries.into_iter())
+}
+
+/// Given a trait `trait_ref`, iterates the vtable entries
+/// that come from `trait_ref`, including its supertraits.
+fn vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+) -> &'tcx [VtblEntry<'tcx>] {
+ debug!("vtable_entries({:?})", trait_ref);
+
+ let mut entries = vec![];
+
+ let vtable_segment_callback = |segment| -> ControlFlow<()> {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES);
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ let existential_trait_ref = trait_ref
+ .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+
+ // Lookup the shape of vtable for the trait.
+ let own_existential_entries =
+ tcx.own_existential_vtable_entries(existential_trait_ref);
+
+ let own_entries = own_existential_entries.iter().copied().map(|def_id| {
+ debug!("vtable_entries: trait_method={:?}", def_id);
+
+ // The method may have some early-bound lifetimes; add regions for those.
+ let substs = trait_ref.map_bound(|trait_ref| {
+ InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+ GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+ GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Const { .. } => {
+ trait_ref.substs[param.index as usize]
+ }
+ })
+ });
+
+ // The trait type may have higher-ranked lifetimes in it;
+ // erase them if they appear, so that we get the type
+ // at some particular call site.
+ let substs = tcx
+ .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+ // It's possible that the method relies on where-clauses that
+ // do not hold for this particular set of type parameters.
+ // Note that this method could then never be called, so we
+ // do not want to try and codegen it, in that case (see #23435).
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+ if impossible_predicates(tcx, predicates.predicates) {
+ debug!("vtable_entries: predicates do not hold");
+ return VtblEntry::Vacant;
+ }
+
+ let instance = ty::Instance::resolve_for_vtable(
+ tcx,
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ substs,
+ )
+ .expect("resolution failed during building vtable representation");
+ VtblEntry::Method(instance)
+ });
+
+ entries.extend(own_entries);
+
+ if emit_vptr {
+ entries.push(VtblEntry::TraitVPtr(trait_ref));
+ }
+ }
+ }
+
+ ControlFlow::Continue(())
+ };
+
+ let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
+
+ if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
+ let sp = tcx.def_span(trait_ref.def_id());
+ dump_vtable_entries(tcx, sp, trait_ref, &entries);
+ }
+
+ tcx.arena.alloc_from_iter(entries.into_iter())
+}
+
+/// Find slot base for trait methods within vtable entries of another trait
+fn vtable_trait_first_method_offset<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (
+ ty::PolyTraitRef<'tcx>, // trait_to_be_found
+ ty::PolyTraitRef<'tcx>, // trait_owning_vtable
+ ),
+) -> usize {
+ let (trait_to_be_found, trait_owning_vtable) = key;
+
+ // #90177
+ let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
+
+ let vtable_segment_callback = {
+ let mut vtable_base = 0;
+
+ move |segment| {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ vtable_base += TyCtxt::COMMON_VTABLE_ENTRIES.len();
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
+ return ControlFlow::Break(vtable_base);
+ }
+ vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
+ if emit_vptr {
+ vtable_base += 1;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+ };
+
+ if let Some(vtable_base) =
+ prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
+ {
+ vtable_base
+ } else {
+ bug!("Failed to find info for expected trait in vtable");
+ }
+}
+
+/// Find slot offset for trait vptr within vtable entries of another trait
+pub fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (
+ Ty<'tcx>, // trait object type whose trait owning vtable
+ Ty<'tcx>, // trait object for supertrait
+ ),
+) -> Option<usize> {
+ let (source, target) = key;
+ assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
+ assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
+
+ // this has been typecked-before, so diagnostics is not really needed.
+ let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
+
+ let trait_ref = ty::TraitRef {
+ def_id: unsize_trait_did,
+ substs: tcx.mk_substs_trait(source, &[target.into()]),
+ };
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ ty::ParamEnv::reveal_all(),
+ ty::Binder::dummy(ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
+ }),
+ );
+
+ let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ selcx.select(&obligation).unwrap()
+ });
+
+ let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
+ bug!();
+ };
+
+ implsrc_traitcasting.vtable_vptr_slot
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ object_safety::provide(providers);
+ structural_match::provide(providers);
+ *providers = ty::query::Providers {
+ specialization_graph_of: specialize::specialization_graph_provider,
+ specializes: specialize::specializes,
+ codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
+ own_existential_vtable_entries,
+ vtable_entries,
+ vtable_trait_upcasting_coercion_new_vptr_slot,
+ subst_and_check_impossible_predicates,
+ try_unify_abstract_consts: |tcx, param_env_and| {
+ let (param_env, (a, b)) = param_env_and.into_parts();
+ const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
+ },
+ ..*providers
+ };
+}
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
new file mode 100644
index 000000000..612f51309
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -0,0 +1,866 @@
+//! "Object safety" refers to the ability for a trait to be converted
+//! to an object. In general, traits may only be converted to an
+//! object if all of their methods meet certain criteria. In particular,
+//! they must:
+//!
+//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version
+//! that doesn't contain the vtable;
+//! - not reference the erased type `Self` except for in this receiver;
+//! - not have generic type parameters.
+
+use super::elaborate_predicates;
+
+use crate::infer::TyCtxtInferExt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{self, Obligation, ObligationCause};
+use rustc_errors::{FatalError, MultiSpan};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
+use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
+use rustc_middle::ty::{
+ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+};
+use rustc_middle::ty::{Predicate, ToPredicate};
+use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
+use rustc_span::symbol::Symbol;
+use rustc_span::Span;
+use smallvec::SmallVec;
+
+use std::iter;
+use std::ops::ControlFlow;
+
+pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
+
+/// Returns the object safety violations that affect
+/// astconv -- currently, `Self` in supertraits. This is needed
+/// because `object_safety_violations` can't be used during
+/// type collection.
+pub fn astconv_object_safety_violations(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+ debug_assert!(tcx.generics_of(trait_def_id).has_self);
+ let violations = traits::supertrait_def_ids(tcx, trait_def_id)
+ .map(|def_id| predicates_reference_self(tcx, def_id, true))
+ .filter(|spans| !spans.is_empty())
+ .map(ObjectSafetyViolation::SupertraitSelf)
+ .collect();
+
+ debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations);
+
+ violations
+}
+
+fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation] {
+ debug_assert!(tcx.generics_of(trait_def_id).has_self);
+ debug!("object_safety_violations: {:?}", trait_def_id);
+
+ tcx.arena.alloc_from_iter(
+ traits::supertrait_def_ids(tcx, trait_def_id)
+ .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)),
+ )
+}
+
+/// We say a method is *vtable safe* if it can be invoked on a trait
+/// 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`.
+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);
+ // Any method that has a `Self: Sized` bound cannot be called.
+ if generics_require_sized_self(tcx, method.def_id) {
+ return false;
+ }
+
+ match virtual_call_violation_for_method(tcx, trait_def_id, method) {
+ None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true,
+ Some(_) => false,
+ }
+}
+
+fn object_safety_violations_for_trait(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+) -> Vec<ObjectSafetyViolation> {
+ // Check methods for violations.
+ let mut violations: Vec<_> = tcx
+ .associated_items(trait_def_id)
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Fn)
+ .filter_map(|item| {
+ object_safety_violation_for_method(tcx, trait_def_id, &item)
+ .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
+ })
+ .filter(|violation| {
+ if let ObjectSafetyViolation::Method(
+ _,
+ MethodViolationCode::WhereClauseReferencesSelf,
+ span,
+ ) = violation
+ {
+ lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
+ false
+ } else {
+ true
+ }
+ })
+ .collect();
+
+ // Check the trait itself.
+ if trait_has_sized_self(tcx, trait_def_id) {
+ // We don't want to include the requirement from `Sized` itself to be `Sized` in the list.
+ let spans = get_sized_bounds(tcx, trait_def_id);
+ violations.push(ObjectSafetyViolation::SizedSelf(spans));
+ }
+ let spans = predicates_reference_self(tcx, trait_def_id, false);
+ if !spans.is_empty() {
+ violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
+ }
+ let spans = bounds_reference_self(tcx, trait_def_id);
+ if !spans.is_empty() {
+ violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
+ }
+
+ violations.extend(
+ tcx.associated_items(trait_def_id)
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Const)
+ .map(|item| {
+ let ident = item.ident(tcx);
+ ObjectSafetyViolation::AssocConst(ident.name, ident.span)
+ }),
+ );
+
+ if !tcx.features().generic_associated_types_extended {
+ violations.extend(
+ tcx.associated_items(trait_def_id)
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Type)
+ .filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
+ .map(|item| {
+ let ident = item.ident(tcx);
+ ObjectSafetyViolation::GAT(ident.name, ident.span)
+ }),
+ );
+ }
+
+ debug!(
+ "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+ trait_def_id, violations
+ );
+
+ violations
+}
+
+/// Lint object-unsafe trait.
+fn lint_object_unsafe_trait(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ trait_def_id: DefId,
+ violation: &ObjectSafetyViolation,
+) {
+ // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
+ // It's also hard to get a use site span, so we use the method definition span.
+ tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| {
+ let mut err = lint.build(&format!(
+ "the trait `{}` cannot be made into an object",
+ tcx.def_path_str(trait_def_id)
+ ));
+ let node = tcx.hir().get_if_local(trait_def_id);
+ let mut spans = MultiSpan::from_span(span);
+ if let Some(hir::Node::Item(item)) = node {
+ spans.push_span_label(item.ident.span, "this trait cannot be made into an object...");
+ spans.push_span_label(span, format!("...because {}", violation.error_msg()));
+ } else {
+ spans.push_span_label(
+ span,
+ format!(
+ "the trait cannot be made into an object because {}",
+ violation.error_msg()
+ ),
+ );
+ };
+ err.span_note(
+ spans,
+ "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
+ call to be resolvable dynamically; for more information visit \
+ <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+ );
+ if node.is_some() {
+ // Only provide the help if its a local trait, otherwise it's not
+ violation.solution(&mut err);
+ }
+ err.emit();
+ });
+}
+
+fn sized_trait_bound_spans<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ bounds: hir::GenericBounds<'tcx>,
+) -> impl 'tcx + Iterator<Item = Span> {
+ bounds.iter().filter_map(move |b| match b {
+ hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None)
+ if trait_has_sized_self(
+ tcx,
+ trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
+ ) =>
+ {
+ // Fetch spans for supertraits that are `Sized`: `trait T: Super`
+ Some(trait_ref.span)
+ }
+ _ => None,
+ })
+}
+
+fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
+ tcx.hir()
+ .get_if_local(trait_def_id)
+ .and_then(|node| match node {
+ hir::Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(.., generics, bounds, _),
+ ..
+ }) => Some(
+ generics
+ .predicates
+ .iter()
+ .filter_map(|pred| {
+ match pred {
+ hir::WherePredicate::BoundPredicate(pred)
+ if pred.bounded_ty.hir_id.owner.to_def_id() == trait_def_id =>
+ {
+ // Fetch spans for trait bounds that are Sized:
+ // `trait T where Self: Pred`
+ Some(sized_trait_bound_spans(tcx, pred.bounds))
+ }
+ _ => None,
+ }
+ })
+ .flatten()
+ // Fetch spans for supertraits that are `Sized`: `trait T: Super`.
+ .chain(sized_trait_bound_spans(tcx, bounds))
+ .collect::<SmallVec<[Span; 1]>>(),
+ ),
+ _ => None,
+ })
+ .unwrap_or_else(SmallVec::new)
+}
+
+fn predicates_reference_self(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+ supertraits_only: bool,
+) -> SmallVec<[Span; 1]> {
+ let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
+ let predicates = if supertraits_only {
+ tcx.super_predicates_of(trait_def_id)
+ } else {
+ tcx.predicates_of(trait_def_id)
+ };
+ predicates
+ .predicates
+ .iter()
+ .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
+ .filter_map(|predicate| predicate_references_self(tcx, predicate))
+ .collect()
+}
+
+fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
+ tcx.associated_items(trait_def_id)
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Type)
+ .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
+ .filter_map(|pred_span| predicate_references_self(tcx, *pred_span))
+ .collect()
+}
+
+fn predicate_references_self<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (predicate, sp): (ty::Predicate<'tcx>, Span),
+) -> Option<Span> {
+ let self_ty = tcx.types.self_param;
+ let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ref data) => {
+ // In the case of a trait predicate, we can skip the "self" type.
+ if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
+ }
+ ty::PredicateKind::Projection(ref data) => {
+ // And similarly for projections. This should be redundant with
+ // the previous check because any projection should have a
+ // matching `Trait` predicate with the same inputs, but we do
+ // the check to be safe.
+ //
+ // It's also won't be redundant if we allow type-generic associated
+ // types for trait objects.
+ //
+ // Note that we *do* allow projection *outputs* to contain
+ // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
+ // we just require the user to specify *both* outputs
+ // in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
+ //
+ // This is ALT2 in issue #56288, see that for discussion of the
+ // possible alternatives.
+ if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
+ }
+ ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ }
+}
+
+fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+ generics_require_sized_self(tcx, trait_def_id)
+}
+
+fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ let Some(sized_def_id) = tcx.lang_items().sized_trait() else {
+ return false; /* No Sized trait, can't require it! */
+ };
+
+ // Search for a predicate like `Self : Sized` amongst the trait bounds.
+ let predicates = tcx.predicates_of(def_id);
+ let predicates = predicates.instantiate_identity(tcx).predicates;
+ elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ref trait_pred) => {
+ trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
+ }
+ ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
+ }
+ })
+}
+
+/// Returns `Some(_)` if this method makes the containing trait not object safe.
+fn object_safety_violation_for_method(
+ tcx: TyCtxt<'_>,
+ trait_def_id: DefId,
+ method: &ty::AssocItem,
+) -> Option<(MethodViolationCode, Span)> {
+ debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
+ // Any method that has a `Self : Sized` requisite is otherwise
+ // exempt from the regulations.
+ if generics_require_sized_self(tcx, method.def_id) {
+ return None;
+ }
+
+ let violation = virtual_call_violation_for_method(tcx, trait_def_id, method);
+ // Get an accurate span depending on the violation.
+ violation.map(|v| {
+ let node = tcx.hir().get_if_local(method.def_id);
+ let span = match (&v, node) {
+ (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
+ (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
+ (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
+ node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
+ }
+ _ => method.ident(tcx).span,
+ };
+ (v, span)
+ })
+}
+
+/// Returns `Some(_)` if this method cannot be called on a trait
+/// 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>(
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ method: &ty::AssocItem,
+) -> Option<MethodViolationCode> {
+ let sig = tcx.fn_sig(method.def_id);
+
+ // The method's first parameter must be named `self`
+ if !method.fn_has_self_parameter {
+ let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
+ generics,
+ kind: hir::TraitItemKind::Fn(sig, _),
+ ..
+ })) = tcx.hir().get_if_local(method.def_id).as_ref()
+ {
+ let sm = tcx.sess.source_map();
+ Some((
+ (
+ format!("&self{}", if sig.decl.inputs.is_empty() { "" } else { ", " }),
+ sm.span_through_char(sig.span, '(').shrink_to_hi(),
+ ),
+ (
+ format!("{} Self: Sized", generics.add_where_or_trailing_comma()),
+ generics.tail_span_for_predicate_suggestion(),
+ ),
+ ))
+ } else {
+ None
+ };
+ return Some(MethodViolationCode::StaticMethod(sugg));
+ }
+
+ 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 {
+ kind: hir::TraitItemKind::Fn(sig, _),
+ ..
+ })) = tcx.hir().get_if_local(method.def_id).as_ref()
+ {
+ Some(sig.decl.inputs[i].span)
+ } else {
+ None
+ };
+ return Some(MethodViolationCode::ReferencesSelfInput(span));
+ }
+ }
+ if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) {
+ return Some(MethodViolationCode::ReferencesSelfOutput);
+ }
+
+ // 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 tcx
+ .predicates_of(method.def_id)
+ .predicates
+ .iter()
+ // A trait object can't claim to live more than the concrete type,
+ // so outlives predicates will always hold.
+ .cloned()
+ .filter(|(p, _)| p.to_opt_type_outlives().is_none())
+ .any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
+ {
+ return Some(MethodViolationCode::WhereClauseReferencesSelf);
+ }
+
+ let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0));
+
+ // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
+ // However, this is already considered object-safe. We allow it as a special case here.
+ // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
+ // `Receiver: Unsize<Receiver[Self => dyn Trait]>`.
+ if receiver_ty != tcx.types.self_param {
+ if !receiver_is_dispatchable(tcx, method, receiver_ty) {
+ let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(sig, _),
+ ..
+ })) = tcx.hir().get_if_local(method.def_id).as_ref()
+ {
+ Some(sig.decl.inputs[0].span)
+ } else {
+ None
+ };
+ return Some(MethodViolationCode::UndispatchableReceiver(span));
+ } else {
+ // Do sanity check to make sure the receiver actually has the layout of a pointer.
+
+ use rustc_target::abi::Abi;
+
+ let param_env = tcx.param_env(method.def_id);
+
+ let abi_of_ty = |ty: Ty<'tcx>| -> Option<Abi> {
+ match tcx.layout_of(param_env.and(ty)) {
+ Ok(layout) => Some(layout.abi),
+ Err(err) => {
+ // #78372
+ tcx.sess.delay_span_bug(
+ tcx.def_span(method.def_id),
+ &format!("error: {}\n while computing layout for type {:?}", err, ty),
+ );
+ None
+ }
+ }
+ };
+
+ // e.g., `Rc<()>`
+ let unit_receiver_ty =
+ receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id);
+
+ match abi_of_ty(unit_receiver_ty) {
+ Some(Abi::Scalar(..)) => (),
+ abi => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(method.def_id),
+ &format!(
+ "receiver when `Self = ()` should have a Scalar ABI; found {:?}",
+ abi
+ ),
+ );
+ }
+ }
+
+ let trait_object_ty =
+ object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic));
+
+ // e.g., `Rc<dyn Trait>`
+ let trait_object_receiver =
+ receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id);
+
+ match abi_of_ty(trait_object_receiver) {
+ Some(Abi::ScalarPair(..)) => (),
+ abi => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(method.def_id),
+ &format!(
+ "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}",
+ trait_object_ty, abi
+ ),
+ );
+ }
+ }
+ }
+ }
+
+ None
+}
+
+/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`.
+/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
+fn receiver_for_self_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ receiver_ty: Ty<'tcx>,
+ self_ty: Ty<'tcx>,
+ method_def_id: DefId,
+) -> Ty<'tcx> {
+ debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id);
+ let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| {
+ if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) }
+ });
+
+ let result = EarlyBinder(receiver_ty).subst(tcx, substs);
+ debug!(
+ "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}",
+ receiver_ty, self_ty, method_def_id, result
+ );
+ result
+}
+
+/// Creates the object type for the current trait. For example,
+/// if the current trait is `Deref`, then this will be
+/// `dyn Deref<Target = Self::Target> + 'static`.
+fn object_ty_for_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ lifetime: ty::Region<'tcx>,
+) -> Ty<'tcx> {
+ debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
+
+ let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
+
+ let trait_predicate = trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
+ });
+
+ let mut associated_types = traits::supertraits(tcx, trait_ref)
+ .flat_map(|super_trait_ref| {
+ tcx.associated_items(super_trait_ref.def_id())
+ .in_definition_order()
+ .map(move |item| (super_trait_ref, item))
+ })
+ .filter(|(_, item)| item.kind == ty::AssocKind::Type)
+ .collect::<Vec<_>>();
+
+ // existential predicates need to be in a specific order
+ associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
+
+ let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
+ // We *can* get bound lifetimes here in cases like
+ // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
+ super_trait_ref.map_bound(|super_trait_ref| {
+ ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+ term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
+ item_def_id: item.def_id,
+ substs: super_trait_ref.substs,
+ })
+ })
+ });
+
+ let existential_predicates = tcx
+ .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
+
+ let object_ty = tcx.mk_dynamic(existential_predicates, lifetime);
+
+ debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
+
+ object_ty
+}
+
+/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
+/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
+/// in the following way:
+/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`,
+/// - require the following bound:
+///
+/// ```ignore (not-rust)
+/// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
+/// ```
+///
+/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
+/// (substitution notation).
+///
+/// Some examples of receiver types and their required obligation:
+/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`,
+/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`,
+/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`.
+///
+/// The only case where the receiver is not dispatchable, but is still a valid receiver
+/// type (just not object-safe), is when there is more than one level of pointer indirection.
+/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
+/// is no way, or at least no inexpensive way, to coerce the receiver from the version where
+/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type
+/// contained by the trait object, because the object that needs to be coerced is behind
+/// a pointer.
+///
+/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
+/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
+/// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>).
+/// Instead, we fudge a little by introducing a new type parameter `U` such that
+/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
+/// Written as a chalk-style query:
+/// ```ignore (not-rust)
+/// forall (U: Trait + ?Sized) {
+/// if (Self: Unsize<U>) {
+/// Receiver: DispatchFromDyn<Receiver[Self => U]>
+/// }
+/// }
+/// ```
+/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
+/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
+/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
+//
+// 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,
+ receiver_ty: Ty<'tcx>,
+) -> bool {
+ debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
+
+ let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
+ let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
+ debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
+ return false;
+ };
+
+ // the type `U` in the query
+ // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now.
+ // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
+ // replace this with `dyn Trait`
+ let unsized_self_ty: Ty<'tcx> =
+ tcx.mk_ty_param(u32::MAX, Symbol::intern("RustaceansAreAwesome"));
+
+ // `Receiver[Self => U]`
+ let unsized_receiver_ty =
+ receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
+
+ // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds
+ // `U: ?Sized` is already implied here
+ let param_env = {
+ let param_env = tcx.param_env(method.def_id);
+
+ // Self: Unsize<U>
+ let unsize_predicate = ty::Binder::dummy(ty::TraitRef {
+ def_id: unsize_did,
+ substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
+ })
+ .without_const()
+ .to_predicate(tcx);
+
+ // U: Trait<Arg1, ..., ArgN>
+ let trait_predicate = {
+ let substs =
+ InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
+ if param.index == 0 {
+ unsized_self_ty.into()
+ } else {
+ tcx.mk_param_from_def(param)
+ }
+ });
+
+ ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
+ .without_const()
+ .to_predicate(tcx)
+ };
+
+ let caller_bounds: Vec<Predicate<'tcx>> =
+ param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]).collect();
+
+ ty::ParamEnv::new(
+ tcx.intern_predicates(&caller_bounds),
+ param_env.reveal(),
+ param_env.constness(),
+ )
+ };
+
+ // Receiver: DispatchFromDyn<Receiver[Self => U]>
+ let obligation = {
+ let predicate = ty::Binder::dummy(ty::TraitRef {
+ def_id: dispatch_from_dyn_did,
+ substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
+ })
+ .without_const()
+ .to_predicate(tcx);
+
+ Obligation::new(ObligationCause::dummy(), param_env, predicate)
+ };
+
+ tcx.infer_ctxt().enter(|ref infcx| {
+ // the receiver is dispatchable iff the obligation holds
+ infcx.predicate_must_hold_modulo_regions(&obligation)
+ })
+}
+
+fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ value: T,
+) -> bool {
+ // This is somewhat subtle. In general, we want to forbid
+ // references to `Self` in the argument and return types,
+ // since the value of `Self` is erased. However, there is one
+ // exception: it is ok to reference `Self` in order to access
+ // an associated type of the current trait, since we retain
+ // the value of those associated types in the object type
+ // itself.
+ //
+ // ```rust
+ // trait SuperTrait {
+ // type X;
+ // }
+ //
+ // trait Trait : SuperTrait {
+ // type Y;
+ // fn foo(&self, x: Self) // bad
+ // fn foo(&self) -> Self // bad
+ // fn foo(&self) -> Option<Self> // bad
+ // fn foo(&self) -> Self::Y // OK, desugars to next example
+ // fn foo(&self) -> <Self as Trait>::Y // OK
+ // fn foo(&self) -> Self::X // OK, desugars to next example
+ // fn foo(&self) -> <Self as SuperTrait>::X // OK
+ // }
+ // ```
+ //
+ // However, it is not as simple as allowing `Self` in a projected
+ // type, because there are illegal ways to use `Self` as well:
+ //
+ // ```rust
+ // trait Trait : SuperTrait {
+ // ...
+ // fn foo(&self) -> <Self as SomeOtherTrait>::X;
+ // }
+ // ```
+ //
+ // Here we will not have the type of `X` recorded in the
+ // object type, and we cannot resolve `Self as SomeOtherTrait`
+ // without knowing what `Self` is.
+
+ struct IllegalSelfTypeVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ supertraits: Option<Vec<DefId>>,
+ }
+
+ impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
+ type BreakTy = ();
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ ty::Param(_) => {
+ if t == self.tcx.types.self_param {
+ ControlFlow::BREAK
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+ ty::Projection(ref data) => {
+ // This is a projected type `<Foo as SomeTrait>::X`.
+
+ // Compute supertraits of current trait lazily.
+ if self.supertraits.is_none() {
+ let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id);
+ self.supertraits = Some(
+ traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
+ );
+ }
+
+ // Determine whether the trait reference `Foo as
+ // SomeTrait` is in fact a supertrait of the
+ // current trait. In that case, this type is
+ // legal, because the type `X` will be specified
+ // in the object type. Note that we can just use
+ // direct equality here because all of these types
+ // are part of the formal parameter listing, and
+ // hence there should be no inference variables.
+ let is_supertrait_of_current_trait = self
+ .supertraits
+ .as_ref()
+ .unwrap()
+ .contains(&data.trait_ref(self.tcx).def_id);
+
+ if is_supertrait_of_current_trait {
+ ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200
+ } else {
+ t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
+ }
+ }
+ _ => t.super_visit_with(self), // walk contained types, if any
+ }
+ }
+
+ fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // Constants can only influence object safety if they reference `Self`.
+ // This is only possible for unevaluated constants, so we walk these here.
+ //
+ // If `AbstractConst::new` returned an error we already failed compilation
+ // so we don't have to emit an additional error here.
+ //
+ // We currently recurse into abstract consts here but do not recurse in
+ // `is_const_evaluatable`. This means that the object safety check is more
+ // liberal than the const eval check.
+ //
+ // This shouldn't really matter though as we can't really use any
+ // constants which are not considered const evaluatable.
+ use rustc_middle::ty::abstract_const::Node;
+ if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
+ walk_abstract_const(self.tcx, ct, |node| match node.root(self.tcx) {
+ Node::Leaf(leaf) => self.visit_const(leaf),
+ Node::Cast(_, _, ty) => self.visit_ty(ty),
+ Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
+ ControlFlow::CONTINUE
+ }
+ })
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+
+ value
+ .visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
+ .is_break()
+}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { object_safety_violations, ..*providers };
+}
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
new file mode 100644
index 000000000..9227bbf01
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -0,0 +1,425 @@
+use rustc_ast::{MetaItem, NestedMetaItem};
+use rustc_attr as attr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{struct_span_err, ErrorGuaranteed};
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{Span, DUMMY_SP};
+
+#[derive(Clone, Debug)]
+pub struct OnUnimplementedFormatString(Symbol);
+
+#[derive(Debug)]
+pub struct OnUnimplementedDirective {
+ pub condition: Option<MetaItem>,
+ pub subcommands: Vec<OnUnimplementedDirective>,
+ pub message: Option<OnUnimplementedFormatString>,
+ pub label: Option<OnUnimplementedFormatString>,
+ pub note: Option<OnUnimplementedFormatString>,
+ pub enclosing_scope: Option<OnUnimplementedFormatString>,
+ pub append_const_msg: Option<Option<Symbol>>,
+}
+
+#[derive(Default)]
+pub struct OnUnimplementedNote {
+ pub message: Option<String>,
+ pub label: Option<String>,
+ pub note: Option<String>,
+ pub enclosing_scope: Option<String>,
+ /// Append a message for `~const Trait` errors. `None` means not requested and
+ /// should fallback to a generic message, `Some(None)` suggests using the default
+ /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+ /// default one..
+ pub append_const_msg: Option<Option<Symbol>>,
+}
+
+fn parse_error(
+ tcx: TyCtxt<'_>,
+ span: Span,
+ message: &str,
+ label: &str,
+ note: Option<&str>,
+) -> ErrorGuaranteed {
+ let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message);
+ diag.span_label(span, label);
+ if let Some(note) = note {
+ diag.note(note);
+ }
+ diag.emit()
+}
+
+impl<'tcx> OnUnimplementedDirective {
+ fn parse(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ items: &[NestedMetaItem],
+ span: Span,
+ is_root: bool,
+ ) -> Result<Self, ErrorGuaranteed> {
+ let mut errored = None;
+ let mut item_iter = items.iter();
+
+ let parse_value = |value_str| {
+ OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
+ };
+
+ let condition = if is_root {
+ None
+ } else {
+ let cond = item_iter
+ .next()
+ .ok_or_else(|| {
+ parse_error(
+ tcx,
+ span,
+ "empty `on`-clause in `#[rustc_on_unimplemented]`",
+ "empty on-clause here",
+ None,
+ )
+ })?
+ .meta_item()
+ .ok_or_else(|| {
+ parse_error(
+ tcx,
+ span,
+ "invalid `on`-clause in `#[rustc_on_unimplemented]`",
+ "invalid on-clause here",
+ None,
+ )
+ })?;
+ 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) {
+ errored = Some(guar);
+ }
+ true
+ });
+ Some(cond.clone())
+ };
+
+ let mut message = None;
+ let mut label = None;
+ let mut note = None;
+ let mut enclosing_scope = None;
+ let mut subcommands = vec![];
+ let mut append_const_msg = None;
+
+ for item in item_iter {
+ if item.has_name(sym::message) && message.is_none() {
+ if let Some(message_) = item.value_str() {
+ message = parse_value(message_)?;
+ continue;
+ }
+ } else if item.has_name(sym::label) && label.is_none() {
+ if let Some(label_) = item.value_str() {
+ label = parse_value(label_)?;
+ continue;
+ }
+ } else if item.has_name(sym::note) && note.is_none() {
+ if let Some(note_) = item.value_str() {
+ note = parse_value(note_)?;
+ continue;
+ }
+ } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() {
+ if let Some(enclosing_scope_) = item.value_str() {
+ enclosing_scope = parse_value(enclosing_scope_)?;
+ continue;
+ }
+ } else if item.has_name(sym::on)
+ && is_root
+ && message.is_none()
+ && label.is_none()
+ && note.is_none()
+ {
+ if let Some(items) = item.meta_item_list() {
+ match Self::parse(tcx, item_def_id, &items, item.span(), false) {
+ Ok(subcommand) => subcommands.push(subcommand),
+ Err(reported) => errored = Some(reported),
+ };
+ continue;
+ }
+ } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+ if let Some(msg) = item.value_str() {
+ append_const_msg = Some(Some(msg));
+ continue;
+ } else if item.is_word() {
+ append_const_msg = Some(None);
+ continue;
+ }
+ }
+
+ // nothing found
+ parse_error(
+ tcx,
+ item.span(),
+ "this attribute must have a valid value",
+ "expected value here",
+ Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#),
+ );
+ }
+
+ if let Some(reported) = errored {
+ Err(reported)
+ } else {
+ Ok(OnUnimplementedDirective {
+ condition,
+ subcommands,
+ message,
+ label,
+ note,
+ enclosing_scope,
+ append_const_msg,
+ })
+ }
+ }
+
+ pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+ let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
+ return Ok(None);
+ };
+
+ let result = if let Some(items) = attr.meta_item_list() {
+ Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
+ } else if let Some(value) = attr.value_str() {
+ Ok(Some(OnUnimplementedDirective {
+ condition: None,
+ message: None,
+ subcommands: vec![],
+ label: Some(OnUnimplementedFormatString::try_parse(
+ tcx,
+ item_def_id,
+ value,
+ attr.span,
+ )?),
+ note: None,
+ enclosing_scope: None,
+ append_const_msg: None,
+ }))
+ } else {
+ let reported =
+ tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
+ return Err(reported);
+ };
+ debug!("of_item({:?}) = {:?}", item_def_id, result);
+ result
+ }
+
+ pub fn evaluate(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ options: &[(Symbol, Option<String>)],
+ ) -> OnUnimplementedNote {
+ let mut message = None;
+ let mut label = None;
+ let mut note = None;
+ let mut enclosing_scope = None;
+ let mut append_const_msg = None;
+ info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
+
+ let options_map: FxHashMap<Symbol, String> =
+ options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).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))
+ },
+ ) {
+ debug!("evaluate: skipping {:?} due to condition", command);
+ continue;
+ }
+ debug!("evaluate: {:?} succeeded", command);
+ if let Some(ref message_) = command.message {
+ message = Some(message_.clone());
+ }
+
+ if let Some(ref label_) = command.label {
+ label = Some(label_.clone());
+ }
+
+ if let Some(ref note_) = command.note {
+ note = Some(note_.clone());
+ }
+
+ if let Some(ref enclosing_scope_) = command.enclosing_scope {
+ enclosing_scope = Some(enclosing_scope_.clone());
+ }
+
+ append_const_msg = command.append_const_msg;
+ }
+
+ 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)),
+ enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
+ append_const_msg,
+ }
+ }
+}
+
+impl<'tcx> OnUnimplementedFormatString {
+ fn try_parse(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ from: Symbol,
+ err_sp: Span,
+ ) -> Result<Self, ErrorGuaranteed> {
+ let result = OnUnimplementedFormatString(from);
+ result.verify(tcx, item_def_id, err_sp)?;
+ Ok(result)
+ }
+
+ fn verify(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ span: Span,
+ ) -> Result<(), ErrorGuaranteed> {
+ let trait_def_id = if tcx.is_trait(item_def_id) {
+ item_def_id
+ } else {
+ tcx.trait_id_of_impl(item_def_id)
+ .expect("expected `on_unimplemented` to correspond to a trait")
+ };
+ let trait_name = tcx.item_name(trait_def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let s = self.0.as_str();
+ let parser = Parser::new(s, None, None, false, ParseMode::Format);
+ let mut result = Ok(());
+ for token in parser {
+ match token {
+ Piece::String(_) => (), // Normal string, no need to check it
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(s) => {
+ match Symbol::intern(s) {
+ // `{Self}` is allowed
+ kw::SelfUpper => (),
+ // `{ThisTraitsName}` is allowed
+ s if s == trait_name => (),
+ // `{from_method}` is allowed
+ sym::from_method => (),
+ // `{from_desugaring}` is allowed
+ sym::from_desugaring => (),
+ // `{ItemContext}` is allowed
+ sym::ItemContext => (),
+ // `{integral}` and `{integer}` and `{float}` are allowed
+ sym::integral | sym::integer_ | sym::float => (),
+ // So is `{A}` if A is a type parameter
+ s => match generics.params.iter().find(|param| param.name == s) {
+ Some(_) => (),
+ None => {
+ let reported = struct_span_err!(
+ tcx.sess,
+ span,
+ E0230,
+ "there is no parameter `{}` on {}",
+ s,
+ if trait_def_id == item_def_id {
+ format!("trait `{}`", trait_name)
+ } else {
+ "impl".to_string()
+ }
+ )
+ .emit();
+ result = Err(reported);
+ }
+ },
+ }
+ }
+ // `{:1}` and `{}` are not to be used
+ Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
+ let reported = struct_span_err!(
+ tcx.sess,
+ span,
+ E0231,
+ "only named substitution parameters are allowed"
+ )
+ .emit();
+ result = Err(reported);
+ }
+ },
+ }
+ }
+
+ result
+ }
+
+ pub fn format(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ options: &FxHashMap<Symbol, String>,
+ ) -> String {
+ let name = tcx.item_name(trait_ref.def_id);
+ let trait_str = tcx.def_path_str(trait_ref.def_id);
+ let generics = tcx.generics_of(trait_ref.def_id);
+ let generic_map = generics
+ .params
+ .iter()
+ .filter_map(|param| {
+ let value = match param.kind {
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+ trait_ref.substs[param.index as usize].to_string()
+ }
+ GenericParamDefKind::Lifetime => return None,
+ };
+ let name = param.name;
+ Some((name, value))
+ })
+ .collect::<FxHashMap<Symbol, String>>();
+ let empty_string = String::new();
+
+ let s = self.0.as_str();
+ let parser = Parser::new(s, None, None, false, ParseMode::Format);
+ let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
+ parser
+ .map(|p| match p {
+ Piece::String(s) => s,
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(s) => {
+ let s = Symbol::intern(s);
+ match generic_map.get(&s) {
+ Some(val) => val,
+ None if s == name => &trait_str,
+ None => {
+ if let Some(val) = options.get(&s) {
+ val
+ } else if s == sym::from_desugaring || s == sym::from_method {
+ // don't break messages using these two arguments incorrectly
+ &empty_string
+ } else if s == sym::ItemContext {
+ &item_context
+ } else if s == sym::integral {
+ "{integral}"
+ } else if s == sym::integer_ {
+ "{integer}"
+ } else if s == sym::float {
+ "{float}"
+ } else {
+ bug!(
+ "broken on_unimplemented {:?} for {:?}: \
+ no argument matching {:?}",
+ self.0,
+ trait_ref,
+ s
+ )
+ }
+ }
+ }
+ }
+ _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
+ },
+ })
+ .collect()
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
new file mode 100644
index 000000000..c4e80e1ba
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -0,0 +1,2150 @@
+//! Code for projecting associated types out of trait references.
+
+use super::specialization_graph;
+use super::translate_substs;
+use super::util;
+use super::MismatchedProjectionTypes;
+use super::Obligation;
+use super::ObligationCause;
+use super::PredicateObligation;
+use super::Selection;
+use super::SelectionContext;
+use super::SelectionError;
+use super::{
+ ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
+ ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
+};
+use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
+
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
+use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::select::ProjectionMatchesProjection;
+use rustc_data_structures::sso::SsoHashSet;
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_middle::traits::select::OverflowError;
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
+use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
+use rustc_span::symbol::sym;
+
+use std::collections::BTreeMap;
+
+pub use rustc_middle::traits::Reveal;
+
+pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
+
+pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
+
+pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>;
+
+pub(super) struct InProgress;
+
+/// When attempting to resolve `<T as TraitRef>::Name` ...
+#[derive(Debug)]
+pub enum ProjectionError<'tcx> {
+ /// ...we found multiple sources of information and couldn't resolve the ambiguity.
+ TooManyCandidates,
+
+ /// ...an error occurred matching `T : TraitRef`
+ TraitSelectionError(SelectionError<'tcx>),
+}
+
+#[derive(PartialEq, Eq, Debug)]
+enum ProjectionCandidate<'tcx> {
+ /// From a where-clause in the env or object type
+ ParamEnv(ty::PolyProjectionPredicate<'tcx>),
+
+ /// From the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
+ TraitDef(ty::PolyProjectionPredicate<'tcx>),
+
+ /// Bounds specified on an object type
+ Object(ty::PolyProjectionPredicate<'tcx>),
+
+ /// From an "impl" (or a "pseudo-impl" returned by select)
+ Select(Selection<'tcx>),
+}
+
+enum ProjectionCandidateSet<'tcx> {
+ None,
+ Single(ProjectionCandidate<'tcx>),
+ Ambiguous,
+ Error(SelectionError<'tcx>),
+}
+
+impl<'tcx> ProjectionCandidateSet<'tcx> {
+ fn mark_ambiguous(&mut self) {
+ *self = ProjectionCandidateSet::Ambiguous;
+ }
+
+ fn mark_error(&mut self, err: SelectionError<'tcx>) {
+ *self = ProjectionCandidateSet::Error(err);
+ }
+
+ // Returns true if the push was successful, or false if the candidate
+ // was discarded -- this could be because of ambiguity, or because
+ // a higher-priority candidate is already there.
+ fn push_candidate(&mut self, candidate: ProjectionCandidate<'tcx>) -> bool {
+ use self::ProjectionCandidate::*;
+ use self::ProjectionCandidateSet::*;
+
+ // This wacky variable is just used to try and
+ // make code readable and avoid confusing paths.
+ // It is assigned a "value" of `()` only on those
+ // paths in which we wish to convert `*self` to
+ // ambiguous (and return false, because the candidate
+ // was not used). On other paths, it is not assigned,
+ // and hence if those paths *could* reach the code that
+ // comes after the match, this fn would not compile.
+ let convert_to_ambiguous;
+
+ match self {
+ None => {
+ *self = Single(candidate);
+ return true;
+ }
+
+ Single(current) => {
+ // Duplicates can happen inside ParamEnv. In the case, we
+ // perform a lazy deduplication.
+ if current == &candidate {
+ return false;
+ }
+
+ // Prefer where-clauses. As in select, if there are multiple
+ // candidates, we prefer where-clause candidates over impls. This
+ // may seem a bit surprising, since impls are the source of
+ // "truth" in some sense, but in fact some of the impls that SEEM
+ // applicable are not, because of nested obligations. Where
+ // clauses are the safer choice. See the comment on
+ // `select::SelectionCandidate` and #21974 for more details.
+ match (current, candidate) {
+ (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (),
+ (ParamEnv(..), _) => return false,
+ (_, ParamEnv(..)) => unreachable!(),
+ (_, _) => convert_to_ambiguous = (),
+ }
+ }
+
+ Ambiguous | Error(..) => {
+ return false;
+ }
+ }
+
+ // We only ever get here when we moved from a single candidate
+ // to ambiguous.
+ let () = convert_to_ambiguous;
+ *self = Ambiguous;
+ false
+ }
+}
+
+/// States returned from `poly_project_and_unify_type`. Takes the place
+/// of the old return type, which was:
+/// ```ignore (not-rust)
+/// Result<
+/// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
+/// MismatchedProjectionTypes<'tcx>,
+/// >
+/// ```
+pub(super) enum ProjectAndUnifyResult<'tcx> {
+ /// The projection bound holds subject to the given obligations. If the
+ /// projection cannot be normalized because the required trait bound does
+ /// not hold, this is returned, with `obligations` being a predicate that
+ /// cannot be proven.
+ Holds(Vec<PredicateObligation<'tcx>>),
+ /// The projection cannot be normalized due to ambiguity. Resolving some
+ /// inference variables in the projection may fix this.
+ FailedNormalization,
+ /// The project cannot be normalized because `poly_project_and_unify_type`
+ /// is called recursively while normalizing the same projection.
+ Recursive,
+ // the projection can be normalized, but is not equal to the expected type.
+ // Returns the type error that arose from the mismatch.
+ MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
+}
+
+/// Evaluates constraints of the form:
+/// ```ignore (not-rust)
+/// for<...> <T as Trait>::U == V
+/// ```
+/// If successful, this may result in additional obligations. Also returns
+/// the projection cache key used to track these additional obligations.
+#[instrument(level = "debug", skip(selcx))]
+pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &PolyProjectionObligation<'tcx>,
+) -> ProjectAndUnifyResult<'tcx> {
+ let infcx = selcx.infcx();
+ let r = infcx.commit_if_ok(|_snapshot| {
+ let old_universe = infcx.universe();
+ let placeholder_predicate =
+ infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ let new_universe = infcx.universe();
+
+ let placeholder_obligation = obligation.with(placeholder_predicate);
+ match project_and_unify_type(selcx, &placeholder_obligation) {
+ ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
+ ProjectAndUnifyResult::Holds(obligations)
+ if old_universe != new_universe
+ && selcx.tcx().features().generic_associated_types_extended =>
+ {
+ // If the `generic_associated_types_extended` feature is active, then we ignore any
+ // obligations references lifetimes from any universe greater than or equal to the
+ // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`,
+ // which isn't quite what we want. Ideally, we want either an implied
+ // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we
+ // substitute concrete regions. There is design work to be done here; until then,
+ // however, this allows experimenting potential GAT features without running into
+ // well-formedness issues.
+ let new_obligations = obligations
+ .into_iter()
+ .filter(|obligation| {
+ let mut visitor = MaxUniverse::new();
+ obligation.predicate.visit_with(&mut visitor);
+ visitor.max_universe() < new_universe
+ })
+ .collect();
+ Ok(ProjectAndUnifyResult::Holds(new_obligations))
+ }
+ other => Ok(other),
+ }
+ });
+
+ match r {
+ Ok(inner) => inner,
+ Err(err) => ProjectAndUnifyResult::MismatchedProjectionTypes(err),
+ }
+}
+
+/// Evaluates constraints of the form:
+/// ```ignore (not-rust)
+/// <T as Trait>::U == V
+/// ```
+/// If successful, this may result in additional obligations.
+///
+/// See [poly_project_and_unify_type] for an explanation of the return value.
+#[tracing::instrument(level = "debug", skip(selcx))]
+fn project_and_unify_type<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionObligation<'tcx>,
+) -> ProjectAndUnifyResult<'tcx> {
+ let mut obligations = vec![];
+
+ let infcx = selcx.infcx();
+ let normalized = match opt_normalize_projection_type(
+ selcx,
+ obligation.param_env,
+ obligation.predicate.projection_ty,
+ obligation.cause.clone(),
+ obligation.recursion_depth,
+ &mut obligations,
+ ) {
+ Ok(Some(n)) => n,
+ Ok(None) => return ProjectAndUnifyResult::FailedNormalization,
+ Err(InProgress) => return ProjectAndUnifyResult::Recursive,
+ };
+ debug!(?normalized, ?obligations, "project_and_unify_type result");
+ let actual = obligation.predicate.term;
+ // For an example where this is neccessary see src/test/ui/impl-trait/nested-return-type2.rs
+ // This allows users to omit re-mentioning all bounds on an associated type and just use an
+ // `impl Trait` for the assoc type to add more bounds.
+ let InferOk { value: actual, obligations: new } =
+ selcx.infcx().replace_opaque_types_with_inference_vars(
+ actual,
+ obligation.cause.body_id,
+ obligation.cause.span,
+ obligation.param_env,
+ );
+ obligations.extend(new);
+
+ match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
+ Ok(InferOk { obligations: inferred_obligations, value: () }) => {
+ obligations.extend(inferred_obligations);
+ ProjectAndUnifyResult::Holds(obligations)
+ }
+ Err(err) => {
+ debug!("equating types encountered error {:?}", err);
+ ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err })
+ }
+ }
+}
+
+/// Normalizes any associated type projections in `value`, replacing
+/// them with a fully resolved type where possible. The return value
+/// combines the normalized result and any additional obligations that
+/// were incurred as result.
+pub fn normalize<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ value: T,
+) -> Normalized<'tcx, T>
+where
+ T: TypeFoldable<'tcx>,
+{
+ let mut obligations = Vec::new();
+ let value = normalize_to(selcx, param_env, cause, value, &mut obligations);
+ Normalized { value, obligations }
+}
+
+pub fn normalize_to<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ value: T,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+ T: TypeFoldable<'tcx>,
+{
+ normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations)
+}
+
+/// As `normalize`, but with a custom depth.
+pub fn normalize_with_depth<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ value: T,
+) -> Normalized<'tcx, T>
+where
+ T: TypeFoldable<'tcx>,
+{
+ let mut obligations = Vec::new();
+ let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
+ Normalized { value, obligations }
+}
+
+#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
+pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ value: T,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+ T: TypeFoldable<'tcx>,
+{
+ debug!(obligations.len = obligations.len());
+ let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
+ let result = ensure_sufficient_stack(|| normalizer.fold(value));
+ debug!(?result, obligations.len = normalizer.obligations.len());
+ debug!(?normalizer.obligations,);
+ result
+}
+
+#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
+pub fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ value: T,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> T
+where
+ T: TypeFoldable<'tcx>,
+{
+ debug!(obligations.len = obligations.len());
+ let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement(
+ selcx,
+ param_env,
+ cause,
+ depth,
+ obligations,
+ );
+ let result = ensure_sufficient_stack(|| normalizer.fold(value));
+ debug!(?result, obligations.len = normalizer.obligations.len());
+ debug!(?normalizer.obligations,);
+ result
+}
+
+pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool {
+ match reveal {
+ Reveal::UserFacing => value
+ .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
+ Reveal::All => value.has_type_flags(
+ ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_OPAQUE
+ | ty::TypeFlags::HAS_CT_PROJECTION,
+ ),
+ }
+}
+
+struct AssocTypeNormalizer<'a, 'b, 'tcx> {
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+ depth: usize,
+ universes: Vec<Option<ty::UniverseIndex>>,
+ /// If true, when a projection is unable to be completed, an inference
+ /// variable will be created and an obligation registered to project to that
+ /// inference variable. Also, constants will be eagerly evaluated.
+ eager_inference_replacement: bool,
+}
+
+impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
+ fn new(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+ ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
+ AssocTypeNormalizer {
+ selcx,
+ param_env,
+ cause,
+ obligations,
+ depth,
+ universes: vec![],
+ eager_inference_replacement: true,
+ }
+ }
+
+ fn new_without_eager_inference_replacement(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &'a mut Vec<PredicateObligation<'tcx>>,
+ ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
+ AssocTypeNormalizer {
+ selcx,
+ param_env,
+ cause,
+ obligations,
+ depth,
+ universes: vec![],
+ eager_inference_replacement: false,
+ }
+ }
+
+ fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ let value = self.selcx.infcx().resolve_vars_if_possible(value);
+ debug!(?value);
+
+ assert!(
+ !value.has_escaping_bound_vars(),
+ "Normalizing {:?} without wrapping in a `Binder`",
+ value
+ );
+
+ if !needs_normalization(&value, self.param_env.reveal()) {
+ value
+ } else {
+ value.fold_with(self)
+ }
+ }
+}
+
+impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
+ fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
+ self.selcx.tcx()
+ }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> ty::Binder<'tcx, T> {
+ self.universes.push(None);
+ let t = t.super_fold_with(self);
+ self.universes.pop();
+ t
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if !needs_normalization(&ty, self.param_env.reveal()) {
+ return ty;
+ }
+
+ // We try to be a little clever here as a performance optimization in
+ // cases where there are nested projections under binders.
+ // For example:
+ // ```
+ // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
+ // ```
+ // We normalize the substs on the projection before the projecting, but
+ // if we're naive, we'll
+ // replace bound vars on inner, project inner, replace placeholders on inner,
+ // replace bound vars on outer, project outer, replace placeholders on outer
+ //
+ // However, if we're a bit more clever, we can replace the bound vars
+ // on the entire type before normalizing nested projections, meaning we
+ // replace bound vars on outer, project inner,
+ // project outer, replace placeholders on outer
+ //
+ // This is possible because the inner `'a` will already be a placeholder
+ // when we need to normalize the inner projection
+ //
+ // On the other hand, this does add a bit of complexity, since we only
+ // replace bound vars if the current type is a `Projection` and we need
+ // to make sure we don't forget to fold the substs regardless.
+
+ match *ty.kind() {
+ // This is really important. While we *can* handle this, this has
+ // severe performance implications for large opaque types with
+ // late-bound regions. See `issue-88862` benchmark.
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
+ // Only normalize `impl Trait` outside of type inference, usually in codegen.
+ match self.param_env.reveal() {
+ Reveal::UserFacing => ty.super_fold_with(self),
+
+ Reveal::All => {
+ let recursion_limit = self.tcx().recursion_limit();
+ if !recursion_limit.value_within_limit(self.depth) {
+ let obligation = Obligation::with_depth(
+ self.cause.clone(),
+ recursion_limit.0,
+ self.param_env,
+ ty,
+ );
+ self.selcx.infcx().report_overflow_error(&obligation, true);
+ }
+
+ let substs = substs.fold_with(self);
+ let generic_ty = self.tcx().bound_type_of(def_id);
+ let concrete_ty = generic_ty.subst(self.tcx(), substs);
+ self.depth += 1;
+ let folded_ty = self.fold_ty(concrete_ty);
+ self.depth -= 1;
+ folded_ty
+ }
+ }
+ }
+
+ ty::Projection(data) if !data.has_escaping_bound_vars() => {
+ // This branch is *mostly* just an optimization: when we don't
+ // have escaping bound vars, we don't need to replace them with
+ // placeholders (see branch below). *Also*, we know that we can
+ // register an obligation to *later* project, since we know
+ // there won't be bound vars there.
+ let data = data.fold_with(self);
+ let normalized_ty = if self.eager_inference_replacement {
+ normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ } else {
+ opt_normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ .ok()
+ .flatten()
+ .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self)))
+ };
+ debug!(
+ ?self.depth,
+ ?ty,
+ ?normalized_ty,
+ obligations.len = ?self.obligations.len(),
+ "AssocTypeNormalizer: normalized type"
+ );
+ normalized_ty.ty().unwrap()
+ }
+
+ ty::Projection(data) => {
+ // If there are escaping bound vars, we temporarily replace the
+ // bound vars with placeholders. Note though, that in the case
+ // that we still can't project for whatever reason (e.g. self
+ // type isn't known enough), we *can't* register an obligation
+ // and return an inference variable (since then that obligation
+ // would have bound vars and that's a can of worms). Instead,
+ // we just give up and fall back to pretending like we never tried!
+ //
+ // Note: this isn't necessarily the final approach here; we may
+ // want to figure out how to register obligations with escaping vars
+ // or handle this some other way.
+
+ let infcx = self.selcx.infcx();
+ let (data, mapped_regions, mapped_types, mapped_consts) =
+ BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ let data = data.fold_with(self);
+ let normalized_ty = opt_normalize_projection_type(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ .ok()
+ .flatten()
+ .map(|term| term.ty().unwrap())
+ .map(|normalized_ty| {
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ normalized_ty,
+ )
+ })
+ .unwrap_or_else(|| ty.super_fold_with(self));
+
+ debug!(
+ ?self.depth,
+ ?ty,
+ ?normalized_ty,
+ obligations.len = ?self.obligations.len(),
+ "AssocTypeNormalizer: normalized type"
+ );
+ normalized_ty
+ }
+
+ _ => ty.super_fold_with(self),
+ }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
+ constant
+ } else {
+ let constant = constant.super_fold_with(self);
+ debug!(?constant);
+ debug!("self.param_env: {:?}", self.param_env);
+ constant.eval(self.selcx.tcx(), self.param_env)
+ }
+ }
+}
+
+pub struct BoundVarReplacer<'me, 'tcx> {
+ infcx: &'me InferCtxt<'me, 'tcx>,
+ // These three maps track the bound variable that were replaced by placeholders. It might be
+ // nice to remove these since we already have the `kind` in the placeholder; we really just need
+ // 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>,
+ // 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,
+ // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
+ // we don't actually create a universe until we see a bound var we have to replace.
+ universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
+}
+
+impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
+ /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
+ /// use a binding level above `universe_indices.len()`, we fail.
+ pub fn replace_bound_vars<T: TypeFoldable<'tcx>>(
+ infcx: &'me InferCtxt<'me, 'tcx>,
+ universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
+ value: T,
+ ) -> (
+ T,
+ BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+ BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+ BTreeMap<ty::PlaceholderConst<'tcx>, 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 mut replacer = BoundVarReplacer {
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ current_index: ty::INNERMOST,
+ universe_indices,
+ };
+
+ let value = value.fold_with(&mut replacer);
+
+ (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
+ }
+
+ fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
+ let infcx = self.infcx;
+ let index =
+ self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
+ let universe = self.universe_indices[index].unwrap_or_else(|| {
+ for i in self.universe_indices.iter_mut().take(index + 1) {
+ *i = i.or_else(|| Some(infcx.create_next_universe()))
+ }
+ self.universe_indices[index].unwrap()
+ });
+ universe
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> ty::Binder<'tcx, T> {
+ self.current_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.current_index.shift_out(1);
+ t
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ match *r {
+ ty::ReLateBound(debruijn, _)
+ if debruijn.as_usize() + 1
+ > self.current_index.as_usize() + self.universe_indices.len() =>
+ {
+ bug!("Bound vars outside of `self.universe_indices`");
+ }
+ ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
+ let universe = self.universe_for(debruijn);
+ let p = ty::PlaceholderRegion { universe, name: br.kind };
+ self.mapped_regions.insert(p, br);
+ self.infcx.tcx.mk_region(ty::RePlaceholder(p))
+ }
+ _ => r,
+ }
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ match *t.kind() {
+ ty::Bound(debruijn, _)
+ if debruijn.as_usize() + 1
+ > self.current_index.as_usize() + self.universe_indices.len() =>
+ {
+ bug!("Bound vars outside of `self.universe_indices`");
+ }
+ ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
+ let universe = self.universe_for(debruijn);
+ let p = ty::PlaceholderType { universe, name: bound_ty.var };
+ self.mapped_types.insert(p, bound_ty);
+ self.infcx.tcx.mk_ty(ty::Placeholder(p))
+ }
+ _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
+ _ => t,
+ }
+ }
+
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ match ct.kind() {
+ ty::ConstKind::Bound(debruijn, _)
+ if debruijn.as_usize() + 1
+ > self.current_index.as_usize() + self.universe_indices.len() =>
+ {
+ bug!("Bound vars outside of `self.universe_indices`");
+ }
+ ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
+ let universe = self.universe_for(debruijn);
+ let p = ty::PlaceholderConst { universe, name: bound_const };
+ self.mapped_consts.insert(p, bound_const);
+ self.infcx
+ .tcx
+ .mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(p), ty: ct.ty() })
+ }
+ _ => ct.super_fold_with(self),
+ }
+ }
+
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
+ }
+}
+
+// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
+pub struct PlaceholderReplacer<'me, 'tcx> {
+ infcx: &'me InferCtxt<'me, 'tcx>,
+ mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+ mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+ mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+ universe_indices: &'me [Option<ty::UniverseIndex>],
+ current_index: ty::DebruijnIndex,
+}
+
+impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
+ pub fn replace_placeholders<T: TypeFoldable<'tcx>>(
+ infcx: &'me InferCtxt<'me, 'tcx>,
+ mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+ mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+ mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+ universe_indices: &'me [Option<ty::UniverseIndex>],
+ value: T,
+ ) -> T {
+ let mut replacer = PlaceholderReplacer {
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ universe_indices,
+ current_index: ty::INNERMOST,
+ };
+ value.fold_with(&mut replacer)
+ }
+}
+
+impl<'tcx> TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> ty::Binder<'tcx, T> {
+ if !t.has_placeholders() && !t.has_infer_regions() {
+ return t;
+ }
+ self.current_index.shift_in(1);
+ let t = t.super_fold_with(self);
+ self.current_index.shift_out(1);
+ t
+ }
+
+ fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ let r1 = match *r0 {
+ ty::ReVar(_) => self
+ .infcx
+ .inner
+ .borrow_mut()
+ .unwrap_region_constraints()
+ .opportunistic_resolve_region(self.infcx.tcx, r0),
+ _ => r0,
+ };
+
+ let r2 = match *r1 {
+ ty::RePlaceholder(p) => {
+ let replace_var = self.mapped_regions.get(&p);
+ match replace_var {
+ Some(replace_var) => {
+ let index = self
+ .universe_indices
+ .iter()
+ .position(|u| matches!(u, Some(pu) if *pu == p.universe))
+ .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
+ let db = ty::DebruijnIndex::from_usize(
+ self.universe_indices.len() - index + self.current_index.as_usize() - 1,
+ );
+ self.tcx().mk_region(ty::ReLateBound(db, *replace_var))
+ }
+ None => r1,
+ }
+ }
+ _ => r1,
+ };
+
+ debug!(?r0, ?r1, ?r2, "fold_region");
+
+ r2
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ match *ty.kind() {
+ ty::Placeholder(p) => {
+ let replace_var = self.mapped_types.get(&p);
+ match replace_var {
+ Some(replace_var) => {
+ let index = self
+ .universe_indices
+ .iter()
+ .position(|u| matches!(u, Some(pu) if *pu == p.universe))
+ .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
+ let db = ty::DebruijnIndex::from_usize(
+ self.universe_indices.len() - index + self.current_index.as_usize() - 1,
+ );
+ self.tcx().mk_ty(ty::Bound(db, *replace_var))
+ }
+ None => ty,
+ }
+ }
+
+ _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
+ _ => ty,
+ }
+ }
+
+ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+ if let ty::ConstKind::Placeholder(p) = ct.kind() {
+ let replace_var = self.mapped_consts.get(&p);
+ match replace_var {
+ Some(replace_var) => {
+ let index = self
+ .universe_indices
+ .iter()
+ .position(|u| matches!(u, Some(pu) if *pu == p.universe))
+ .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
+ let db = ty::DebruijnIndex::from_usize(
+ self.universe_indices.len() - index + self.current_index.as_usize() - 1,
+ );
+ self.tcx().mk_const(ty::ConstS {
+ kind: ty::ConstKind::Bound(db, *replace_var),
+ ty: ct.ty(),
+ })
+ }
+ None => ct,
+ }
+ } else {
+ ct.super_fold_with(self)
+ }
+ }
+}
+
+/// The guts of `normalize`: normalize a specific projection like `<T
+/// as Trait>::Item`. The result is always a type (and possibly
+/// additional obligations). If ambiguity arises, which implies that
+/// there are unresolved type variables in the projection, we will
+/// substitute a fresh type variable `$X` and generate a new
+/// obligation `<T as Trait>::Item == $X` for later.
+pub fn normalize_projection_type<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ projection_ty: ty::ProjectionTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> Term<'tcx> {
+ opt_normalize_projection_type(
+ selcx,
+ param_env,
+ projection_ty,
+ cause.clone(),
+ depth,
+ obligations,
+ )
+ .ok()
+ .flatten()
+ .unwrap_or_else(move || {
+ // if we bottom out in ambiguity, create a type variable
+ // and a deferred predicate to resolve this when more type
+ // information is available.
+
+ selcx
+ .infcx()
+ .infer_projection(param_env, projection_ty, cause, depth + 1, obligations)
+ .into()
+ })
+}
+
+/// The guts of `normalize`: normalize a specific projection like `<T
+/// as Trait>::Item`. The result is always a type (and possibly
+/// additional obligations). Returns `None` in the case of ambiguity,
+/// which indicates that there are unbound type variables.
+///
+/// This function used to return `Option<NormalizedTy<'tcx>>`, which contains a
+/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very
+/// often immediately appended to another obligations vector. So now this
+/// function takes an obligations vector and appends to it directly, which is
+/// slightly uglier but avoids the need for an extra short-lived allocation.
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
+fn opt_normalize_projection_type<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ projection_ty: ty::ProjectionTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> Result<Option<Term<'tcx>>, InProgress> {
+ let infcx = selcx.infcx();
+ // Don't use the projection cache in intercrate mode -
+ // the `infcx` may be re-used between intercrate in non-intercrate
+ // mode, which could lead to using incorrect cache results.
+ let use_cache = !selcx.is_intercrate();
+
+ let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
+ let cache_key = ProjectionCacheKey::new(projection_ty);
+
+ // FIXME(#20304) For now, I am caching here, which is good, but it
+ // means we don't capture the type variables that are created in
+ // the case of ambiguity. Which means we may create a large stream
+ // of such variables. OTOH, if we move the caching up a level, we
+ // would not benefit from caching when proving `T: Trait<U=Foo>`
+ // bounds. It might be the case that we want two distinct caches,
+ // or else another kind of cache entry.
+
+ let cache_result = if use_cache {
+ infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
+ } else {
+ Ok(())
+ };
+ match cache_result {
+ Ok(()) => debug!("no cache"),
+ Err(ProjectionCacheEntry::Ambiguous) => {
+ // If we found ambiguity the last time, that means we will continue
+ // to do so until some type in the key changes (and we know it
+ // hasn't, because we just fully resolved it).
+ debug!("found cache entry: ambiguous");
+ return Ok(None);
+ }
+ Err(ProjectionCacheEntry::InProgress) => {
+ // Under lazy normalization, this can arise when
+ // bootstrapping. That is, imagine an environment with a
+ // where-clause like `A::B == u32`. Now, if we are asked
+ // to normalize `A::B`, we will want to check the
+ // where-clauses in scope. So we will try to unify `A::B`
+ // with `A::B`, which can trigger a recursive
+ // normalization.
+
+ debug!("found cache entry: in-progress");
+
+ // Cache that normalizing this projection resulted in a cycle. This
+ // should ensure that, unless this happens within a snapshot that's
+ // rolled back, fulfillment or evaluation will notice the cycle.
+
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().recur(cache_key);
+ }
+ return Err(InProgress);
+ }
+ Err(ProjectionCacheEntry::Recur) => {
+ debug!("recur cache");
+ return Err(InProgress);
+ }
+ Err(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
+ // This is the hottest path in this function.
+ //
+ // If we find the value in the cache, then return it along
+ // with the obligations that went along with it. Note
+ // that, when using a fulfillment context, these
+ // obligations could in principle be ignored: they have
+ // already been registered when the cache entry was
+ // created (and hence the new ones will quickly be
+ // discarded as duplicated). But when doing trait
+ // evaluation this is not the case, and dropping the trait
+ // evaluations can causes ICEs (e.g., #43132).
+ debug!(?ty, "found normalized ty");
+ obligations.extend(ty.obligations);
+ return Ok(Some(ty.value));
+ }
+ Err(ProjectionCacheEntry::Error) => {
+ debug!("opt_normalize_projection_type: found error");
+ let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+ obligations.extend(result.obligations);
+ return Ok(Some(result.value.into()));
+ }
+ }
+
+ let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
+
+ match project(selcx, &obligation) {
+ Ok(Projected::Progress(Progress {
+ term: projected_term,
+ obligations: mut projected_obligations,
+ })) => {
+ // if projection succeeded, then what we get out of this
+ // is also non-normalized (consider: it was derived from
+ // an impl, where-clause etc) and hence we must
+ // re-normalize it
+
+ let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term);
+
+ let mut result = if projected_term.has_projections() {
+ let mut normalizer = AssocTypeNormalizer::new(
+ selcx,
+ param_env,
+ cause,
+ depth + 1,
+ &mut projected_obligations,
+ );
+ let normalized_ty = normalizer.fold(projected_term);
+
+ Normalized { value: normalized_ty, obligations: projected_obligations }
+ } else {
+ Normalized { value: projected_term, obligations: projected_obligations }
+ };
+
+ let mut deduped: SsoHashSet<_> = Default::default();
+ result.obligations.drain_filter(|projected_obligation| {
+ if !deduped.insert(projected_obligation.clone()) {
+ return true;
+ }
+ false
+ });
+
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
+ }
+ obligations.extend(result.obligations);
+ Ok(Some(result.value))
+ }
+ Ok(Projected::NoProgress(projected_ty)) => {
+ let result = Normalized { value: projected_ty, obligations: vec![] };
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
+ }
+ // No need to extend `obligations`.
+ Ok(Some(result.value))
+ }
+ Err(ProjectionError::TooManyCandidates) => {
+ debug!("opt_normalize_projection_type: too many candidates");
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
+ }
+ Ok(None)
+ }
+ Err(ProjectionError::TraitSelectionError(_)) => {
+ debug!("opt_normalize_projection_type: ERROR");
+ // if we got an error processing the `T as Trait` part,
+ // just return `ty::err` but add the obligation `T :
+ // Trait`, which when processed will cause the error to be
+ // reported later
+
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().error(cache_key);
+ }
+ let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+ obligations.extend(result.obligations);
+ Ok(Some(result.value.into()))
+ }
+ }
+}
+
+/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
+/// hold. In various error cases, we cannot generate a valid
+/// normalized projection. Therefore, we create an inference variable
+/// return an associated obligation that, when fulfilled, will lead to
+/// an error.
+///
+/// Note that we used to return `Error` here, but that was quite
+/// dubious -- the premise was that an error would *eventually* be
+/// reported, when the obligation was processed. But in general once
+/// you see an `Error` you are supposed to be able to assume that an
+/// error *has been* reported, so that you can take whatever heuristic
+/// paths you want to take. To make things worse, it was possible for
+/// cycles to arise, where you basically had a setup like `<MyType<$0>
+/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as
+/// Trait>::Foo> to `[type error]` would lead to an obligation of
+/// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report
+/// an error for this obligation, but we legitimately should not,
+/// because it contains `[type error]`. Yuck! (See issue #29857 for
+/// one case where this arose.)
+fn normalize_to_error<'a, 'tcx>(
+ selcx: &mut SelectionContext<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ projection_ty: ty::ProjectionTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+) -> NormalizedTy<'tcx> {
+ let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx()));
+ let trait_obligation = Obligation {
+ cause,
+ recursion_depth: depth,
+ param_env,
+ predicate: trait_ref.without_const().to_predicate(selcx.tcx()),
+ };
+ let tcx = selcx.infcx().tcx;
+ let def_id = projection_ty.item_def_id;
+ let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::NormalizeProjectionType,
+ span: tcx.def_span(def_id),
+ });
+ Normalized { value: new_value, obligations: vec![trait_obligation] }
+}
+
+enum Projected<'tcx> {
+ Progress(Progress<'tcx>),
+ NoProgress(ty::Term<'tcx>),
+}
+
+struct Progress<'tcx> {
+ term: ty::Term<'tcx>,
+ obligations: Vec<PredicateObligation<'tcx>>,
+}
+
+impl<'tcx> Progress<'tcx> {
+ fn error(tcx: TyCtxt<'tcx>) -> Self {
+ Progress { term: tcx.ty_error().into(), obligations: vec![] }
+ }
+
+ fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
+ self.obligations.append(&mut obligations);
+ self
+ }
+}
+
+/// Computes the result of a projection type (if we can).
+///
+/// IMPORTANT:
+/// - `obligation` must be fully normalized
+#[tracing::instrument(level = "info", skip(selcx))]
+fn project<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
+ if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) {
+ // This should really be an immediate error, but some existing code
+ // relies on being able to recover from this.
+ return Err(ProjectionError::TraitSelectionError(SelectionError::Overflow(
+ OverflowError::Canonical,
+ )));
+ }
+
+ if obligation.predicate.references_error() {
+ return Ok(Projected::Progress(Progress::error(selcx.tcx())));
+ }
+
+ let mut candidates = ProjectionCandidateSet::None;
+
+ // Make sure that the following procedures are kept in order. ParamEnv
+ // needs to be first because it has highest priority, and Select checks
+ // the return value of push_candidate which assumes it's ran at last.
+ assemble_candidates_from_param_env(selcx, obligation, &mut candidates);
+
+ assemble_candidates_from_trait_def(selcx, obligation, &mut candidates);
+
+ assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
+
+ if let ProjectionCandidateSet::Single(ProjectionCandidate::Object(_)) = candidates {
+ // Avoid normalization cycle from selection (see
+ // `assemble_candidates_from_object_ty`).
+ // FIXME(lazy_normalization): Lazy normalization should save us from
+ // having to special case this.
+ } else {
+ assemble_candidates_from_impls(selcx, obligation, &mut candidates);
+ };
+
+ match candidates {
+ ProjectionCandidateSet::Single(candidate) => {
+ Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
+ }
+ ProjectionCandidateSet::None => Ok(Projected::NoProgress(
+ // FIXME(associated_const_generics): this may need to change in the future?
+ // need to investigate whether or not this is fine.
+ selcx
+ .tcx()
+ .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs)
+ .into(),
+ )),
+ // Error occurred while trying to processing impls.
+ ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)),
+ // Inherent ambiguity that prevents us from even enumerating the
+ // candidates.
+ ProjectionCandidateSet::Ambiguous => Err(ProjectionError::TooManyCandidates),
+ }
+}
+
+/// The first thing we have to do is scan through the parameter
+/// environment to see whether there are any projection predicates
+/// there that can answer this question.
+fn assemble_candidates_from_param_env<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+ assemble_candidates_from_predicates(
+ selcx,
+ obligation,
+ candidate_set,
+ ProjectionCandidate::ParamEnv,
+ obligation.param_env.caller_bounds().iter(),
+ false,
+ );
+}
+
+/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
+/// that the definition of `Foo` has some clues:
+///
+/// ```ignore (illustrative)
+/// trait Foo {
+/// type FooT : Bar<BarT=i32>
+/// }
+/// ```
+///
+/// Here, for example, we could conclude that the result is `i32`.
+fn assemble_candidates_from_trait_def<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+ debug!("assemble_candidates_from_trait_def(..)");
+
+ let tcx = selcx.tcx();
+ // Check whether the self-type is itself a projection.
+ // If so, extract what we know from the trait and try to come up with a good answer.
+ let bounds = match *obligation.predicate.self_ty().kind() {
+ ty::Projection(ref data) => tcx.bound_item_bounds(data.item_def_id).subst(tcx, data.substs),
+ ty::Opaque(def_id, substs) => tcx.bound_item_bounds(def_id).subst(tcx, substs),
+ ty::Infer(ty::TyVar(_)) => {
+ // If the self-type is an inference variable, then it MAY wind up
+ // being a projected type, so induce an ambiguity.
+ candidate_set.mark_ambiguous();
+ return;
+ }
+ _ => return,
+ };
+
+ assemble_candidates_from_predicates(
+ selcx,
+ obligation,
+ candidate_set,
+ ProjectionCandidate::TraitDef,
+ bounds.iter(),
+ true,
+ );
+}
+
+/// In the case of a trait object like
+/// `<dyn Iterator<Item = ()> as Iterator>::Item` we can use the existential
+/// predicate in the trait object.
+///
+/// We don't go through the select candidate for these bounds to avoid cycles:
+/// In the above case, `dyn Iterator<Item = ()>: Iterator` would create a
+/// nested obligation of `<dyn Iterator<Item = ()> as Iterator>::Item: Sized`,
+/// this then has to be normalized without having to prove
+/// `dyn Iterator<Item = ()>: Iterator` again.
+fn assemble_candidates_from_object_ty<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+ debug!("assemble_candidates_from_object_ty(..)");
+
+ let tcx = selcx.tcx();
+
+ let self_ty = obligation.predicate.self_ty();
+ let object_ty = selcx.infcx().shallow_resolve(self_ty);
+ let data = match object_ty.kind() {
+ ty::Dynamic(data, ..) => data,
+ ty::Infer(ty::TyVar(_)) => {
+ // If the self-type is an inference variable, then it MAY wind up
+ // being an object type, so induce an ambiguity.
+ candidate_set.mark_ambiguous();
+ return;
+ }
+ _ => return,
+ };
+ let env_predicates = data
+ .projection_bounds()
+ .filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id)
+ .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
+
+ assemble_candidates_from_predicates(
+ selcx,
+ obligation,
+ candidate_set,
+ ProjectionCandidate::Object,
+ env_predicates,
+ false,
+ );
+}
+
+#[tracing::instrument(
+ level = "debug",
+ skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
+)]
+fn assemble_candidates_from_predicates<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+ ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>,
+ env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+ potentially_unnormalized_candidates: bool,
+) {
+ let infcx = selcx.infcx();
+ for predicate in env_predicates {
+ let bound_predicate = predicate.kind();
+ if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
+ let data = bound_predicate.rebind(data);
+ if data.projection_def_id() != obligation.predicate.item_def_id {
+ continue;
+ }
+
+ let is_match = infcx.probe(|_| {
+ selcx.match_projection_projections(
+ obligation,
+ data,
+ potentially_unnormalized_candidates,
+ )
+ });
+
+ match is_match {
+ ProjectionMatchesProjection::Yes => {
+ candidate_set.push_candidate(ctor(data));
+
+ if potentially_unnormalized_candidates
+ && !obligation.predicate.has_infer_types_or_consts()
+ {
+ // HACK: Pick the first trait def candidate for a fully
+ // inferred predicate. This is to allow duplicates that
+ // differ only in normalization.
+ return;
+ }
+ }
+ ProjectionMatchesProjection::Ambiguous => {
+ candidate_set.mark_ambiguous();
+ }
+ ProjectionMatchesProjection::No => {}
+ }
+ }
+ }
+}
+
+#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))]
+fn assemble_candidates_from_impls<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+ // If we are resolving `<T as TraitRef<...>>::Item == Type`,
+ // start out by selecting the predicate `T as TraitRef<...>`:
+ let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
+ let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
+ let _ = selcx.infcx().commit_if_ok(|_| {
+ let impl_source = match selcx.select(&trait_obligation) {
+ Ok(Some(impl_source)) => impl_source,
+ Ok(None) => {
+ candidate_set.mark_ambiguous();
+ return Err(());
+ }
+ Err(e) => {
+ debug!(error = ?e, "selection error");
+ candidate_set.mark_error(e);
+ return Err(());
+ }
+ };
+
+ let eligible = match &impl_source {
+ super::ImplSource::Closure(_)
+ | super::ImplSource::Generator(_)
+ | super::ImplSource::FnPointer(_)
+ | super::ImplSource::TraitAlias(_) => true,
+ super::ImplSource::UserDefined(impl_data) => {
+ // We have to be careful when projecting out of an
+ // impl because of specialization. If we are not in
+ // codegen (i.e., projection mode is not "any"), and the
+ // impl's type is declared as default, then we disable
+ // projection (even if the trait ref is fully
+ // monomorphic). In the case where trait ref is not
+ // fully monomorphic (i.e., includes type parameters),
+ // this is because those type parameters may
+ // ultimately be bound to types from other crates that
+ // may have specialized impls we can't see. In the
+ // case where the trait ref IS fully monomorphic, this
+ // is a policy decision that we made in the RFC in
+ // order to preserve flexibility for the crate that
+ // defined the specializable impl to specialize later
+ // for existing types.
+ //
+ // In either case, we handle this by not adding a
+ // candidate for an impl if it contains a `default`
+ // type.
+ //
+ // NOTE: This should be kept in sync with the similar code in
+ // `rustc_ty_utils::instance::resolve_associated_item()`.
+ let node_item =
+ assoc_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id)
+ .map_err(|ErrorGuaranteed { .. }| ())?;
+
+ if node_item.is_final() {
+ // Non-specializable items are always projectable.
+ true
+ } else {
+ // Only reveal a specializable default if we're past type-checking
+ // and the obligation is monomorphic, otherwise passes such as
+ // transmute checking and polymorphic MIR optimizations could
+ // get a result which isn't correct for all monomorphizations.
+ if obligation.param_env.reveal() == Reveal::All {
+ // NOTE(eddyb) inference variables can resolve to parameters, so
+ // assume `poly_trait_ref` isn't monomorphic, if it contains any.
+ let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(poly_trait_ref);
+ !poly_trait_ref.still_further_specializable()
+ } else {
+ debug!(
+ assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
+ ?obligation.predicate,
+ "assemble_candidates_from_impls: not eligible due to default",
+ );
+ false
+ }
+ }
+ }
+ super::ImplSource::DiscriminantKind(..) => {
+ // While `DiscriminantKind` is automatically implemented for every type,
+ // the concrete discriminant may not be known yet.
+ //
+ // Any type with multiple potential discriminant types is therefore not eligible.
+ let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+ match self_ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Adt(..)
+ | ty::Foreign(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ | ty::Tuple(..)
+ // Integers and floats always have `u8` as their discriminant.
+ | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+ ty::Projection(..)
+ | ty::Opaque(..)
+ | ty::Param(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(..)
+ | ty::Error(_) => false,
+ }
+ }
+ super::ImplSource::Pointee(..) => {
+ // While `Pointee` is automatically implemented for every type,
+ // the concrete metadata type may not be known yet.
+ //
+ // Any type with multiple potential metadata types is therefore not eligible.
+ let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+ let tail = selcx.tcx().struct_tail_with_normalize(
+ self_ty,
+ |ty| {
+ // We throw away any obligations we get from this, since we normalize
+ // and confirm these obligations once again during confirmation
+ normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ )
+ .value
+ },
+ || {},
+ );
+
+ match tail.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ // Extern types have unit metadata, according to RFC 2850
+ | ty::Foreign(_)
+ // If returned by `struct_tail_without_normalization` this is a unit struct
+ // without any fields, or not a struct, and therefore is Sized.
+ | ty::Adt(..)
+ // If returned by `struct_tail_without_normalization` this is the empty tuple.
+ | ty::Tuple(..)
+ // Integers and floats are always Sized, and so have unit type metadata.
+ | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+ // type parameters, opaques, and unnormalized projections have pointer
+ // metadata if they're known (e.g. by the param_env) to be sized
+ ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
+ if selcx.infcx().predicate_must_hold_modulo_regions(
+ &obligation.with(
+ ty::Binder::dummy(ty::TraitRef::new(
+ selcx.tcx().require_lang_item(LangItem::Sized, None),
+ selcx.tcx().mk_substs_trait(self_ty, &[]),
+ ))
+ .without_const()
+ .to_predicate(selcx.tcx()),
+ ),
+ ) =>
+ {
+ true
+ }
+
+ // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
+ ty::Param(_)
+ | ty::Projection(..)
+ | ty::Opaque(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(..)
+ | ty::Error(_) => {
+ if tail.has_infer_types() {
+ candidate_set.mark_ambiguous();
+ }
+ false
+ }
+ }
+ }
+ super::ImplSource::Param(..) => {
+ // This case tell us nothing about the value of an
+ // associated type. Consider:
+ //
+ // ```
+ // trait SomeTrait { type Foo; }
+ // fn foo<T:SomeTrait>(...) { }
+ // ```
+ //
+ // If the user writes `<T as SomeTrait>::Foo`, then the `T
+ // : SomeTrait` binding does not help us decide what the
+ // type `Foo` is (at least, not more specifically than
+ // what we already knew).
+ //
+ // But wait, you say! What about an example like this:
+ //
+ // ```
+ // fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
+ // ```
+ //
+ // Doesn't the `T : SomeTrait<Foo=usize>` predicate help
+ // resolve `T::Foo`? And of course it does, but in fact
+ // that single predicate is desugared into two predicates
+ // in the compiler: a trait predicate (`T : SomeTrait`) and a
+ // projection. And the projection where clause is handled
+ // in `assemble_candidates_from_param_env`.
+ false
+ }
+ super::ImplSource::Object(_) => {
+ // Handled by the `Object` projection candidate. See
+ // `assemble_candidates_from_object_ty` for an explanation of
+ // why we special case object types.
+ false
+ }
+ super::ImplSource::AutoImpl(..)
+ | super::ImplSource::Builtin(..)
+ | super::ImplSource::TraitUpcasting(_)
+ | super::ImplSource::ConstDestruct(_) => {
+ // These traits have no associated types.
+ selcx.tcx().sess.delay_span_bug(
+ obligation.cause.span,
+ &format!("Cannot project an associated type from `{:?}`", impl_source),
+ );
+ return Err(());
+ }
+ };
+
+ if eligible {
+ if candidate_set.push_candidate(ProjectionCandidate::Select(impl_source)) {
+ Ok(())
+ } else {
+ Err(())
+ }
+ } else {
+ Err(())
+ }
+ });
+}
+
+fn confirm_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ candidate: ProjectionCandidate<'tcx>,
+) -> Progress<'tcx> {
+ debug!(?obligation, ?candidate, "confirm_candidate");
+ let mut progress = match candidate {
+ ProjectionCandidate::ParamEnv(poly_projection)
+ | ProjectionCandidate::Object(poly_projection) => {
+ confirm_param_env_candidate(selcx, obligation, poly_projection, false)
+ }
+
+ ProjectionCandidate::TraitDef(poly_projection) => {
+ confirm_param_env_candidate(selcx, obligation, poly_projection, true)
+ }
+
+ ProjectionCandidate::Select(impl_source) => {
+ confirm_select_candidate(selcx, obligation, impl_source)
+ }
+ };
+
+ // When checking for cycle during evaluation, we compare predicates with
+ // "syntactic" equality. Since normalization generally introduces a type
+ // with new region variables, we need to resolve them to existing variables
+ // when possible for this to work. See `auto-trait-projection-recursion.rs`
+ // for a case where this matters.
+ if progress.term.has_infer_regions() {
+ progress.term =
+ progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx()));
+ }
+ progress
+}
+
+fn confirm_select_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ impl_source: Selection<'tcx>,
+) -> Progress<'tcx> {
+ match impl_source {
+ super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
+ super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data),
+ super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data),
+ super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data),
+ super::ImplSource::DiscriminantKind(data) => {
+ confirm_discriminant_kind_candidate(selcx, obligation, data)
+ }
+ super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
+ super::ImplSource::Object(_)
+ | super::ImplSource::AutoImpl(..)
+ | super::ImplSource::Param(..)
+ | super::ImplSource::Builtin(..)
+ | super::ImplSource::TraitUpcasting(_)
+ | super::ImplSource::TraitAlias(..)
+ | super::ImplSource::ConstDestruct(_) => {
+ // we don't create Select candidates with this kind of resolution
+ span_bug!(
+ obligation.cause.span,
+ "Cannot project an associated type from `{:?}`",
+ impl_source
+ )
+ }
+ }
+}
+
+fn confirm_generator_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ impl_source: ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+ let gen_sig = impl_source.substs.as_generator().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_generator_candidate");
+
+ let tcx = selcx.tcx();
+
+ let gen_def_id = tcx.require_lang_item(LangItem::Generator, None);
+
+ let predicate = super::util::generator_trait_ref_and_outputs(
+ tcx,
+ gen_def_id,
+ obligation.predicate.self_ty(),
+ gen_sig,
+ )
+ .map_bound(|(trait_ref, yield_ty, return_ty)| {
+ let name = tcx.associated_item(obligation.predicate.item_def_id).name;
+ let ty = if name == sym::Return {
+ return_ty
+ } else if name == sym::Yield {
+ yield_ty
+ } else {
+ bug!()
+ };
+
+ ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ substs: trait_ref.substs,
+ item_def_id: obligation.predicate.item_def_id,
+ },
+ term: ty.into(),
+ }
+ });
+
+ confirm_param_env_candidate(selcx, obligation, predicate, false)
+ .with_addl_obligations(impl_source.nested)
+ .with_addl_obligations(obligations)
+}
+
+fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ _: ImplSourceDiscriminantKindData,
+) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
+
+ let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+ // We get here from `poly_project_and_unify_type` which replaces bound vars
+ // with placeholders
+ debug_assert!(!self_ty.has_escaping_bound_vars());
+ let substs = tcx.mk_substs([self_ty.into()].iter());
+
+ let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
+
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
+ term: self_ty.discriminant_ty(tcx).into(),
+ };
+
+ // We get here from `poly_project_and_unify_type` which replaces bound vars
+ // with placeholders, so dummy is okay here.
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+}
+
+fn confirm_pointee_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ _: ImplSourcePointeeData,
+) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
+ let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+ let mut obligations = vec![];
+ let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ &mut obligations,
+ )
+ });
+ if check_is_sized {
+ let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
+ tcx.require_lang_item(LangItem::Sized, None),
+ tcx.mk_substs_trait(self_ty, &[]),
+ ))
+ .without_const()
+ .to_predicate(tcx);
+ obligations.push(Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ sized_predicate,
+ ));
+ }
+
+ let substs = tcx.mk_substs([self_ty.into()].iter());
+ let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+
+ let predicate = ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
+ term: metadata_ty.into(),
+ };
+
+ confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+ .with_addl_obligations(obligations)
+}
+
+fn confirm_fn_pointer_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ fn_pointer_impl_source: ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+ let fn_type = selcx.infcx().shallow_resolve(fn_pointer_impl_source.fn_ty);
+ let sig = fn_type.fn_sig(selcx.tcx());
+ let Normalized { value: sig, obligations } = normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ sig,
+ );
+
+ confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
+ .with_addl_obligations(fn_pointer_impl_source.nested)
+ .with_addl_obligations(obligations)
+}
+
+fn confirm_closure_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ impl_source: ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+ let closure_sig = impl_source.substs.as_closure().sig();
+ let Normalized { value: closure_sig, obligations } = normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ closure_sig,
+ );
+
+ debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
+
+ confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
+ .with_addl_obligations(impl_source.nested)
+ .with_addl_obligations(obligations)
+}
+
+fn confirm_callable_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ fn_sig: ty::PolyFnSig<'tcx>,
+ flag: util::TupleArgumentsFlag,
+) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
+
+ debug!(?obligation, ?fn_sig, "confirm_callable_candidate");
+
+ let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None);
+ let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None);
+
+ let predicate = super::util::closure_trait_ref_and_return_type(
+ tcx,
+ fn_once_def_id,
+ obligation.predicate.self_ty(),
+ fn_sig,
+ flag,
+ )
+ .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ substs: trait_ref.substs,
+ item_def_id: fn_once_output_def_id,
+ },
+ term: ret_type.into(),
+ });
+
+ confirm_param_env_candidate(selcx, obligation, predicate, true)
+}
+
+fn confirm_param_env_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
+ potentially_unnormalized_candidate: bool,
+) -> Progress<'tcx> {
+ let infcx = selcx.infcx();
+ let cause = &obligation.cause;
+ let param_env = obligation.param_env;
+
+ let cache_entry = infcx.replace_bound_vars_with_fresh_vars(
+ cause.span,
+ LateBoundRegionConversionTime::HigherRankedType,
+ poly_cache_entry,
+ );
+
+ let cache_projection = cache_entry.projection_ty;
+ let mut nested_obligations = Vec::new();
+ let obligation_projection = obligation.predicate;
+ let obligation_projection = ensure_sufficient_stack(|| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_projection,
+ &mut nested_obligations,
+ )
+ });
+ let cache_projection = if potentially_unnormalized_candidate {
+ ensure_sufficient_stack(|| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ cache_projection,
+ &mut nested_obligations,
+ )
+ })
+ } else {
+ cache_projection
+ };
+
+ debug!(?cache_projection, ?obligation_projection);
+
+ match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
+ Ok(InferOk { value: _, obligations }) => {
+ nested_obligations.extend(obligations);
+ assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
+ // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
+ // a term instead.
+ Progress { term: cache_entry.term, obligations: nested_obligations }
+ }
+ Err(e) => {
+ let msg = format!(
+ "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",
+ obligation, poly_cache_entry, e,
+ );
+ debug!("confirm_param_env_candidate: {}", msg);
+ let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
+ Progress { term: err.into(), obligations: vec![] }
+ }
+ }
+}
+
+fn confirm_impl_candidate<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+ let tcx = selcx.tcx();
+
+ let ImplSourceUserDefinedData { impl_def_id, substs, mut nested } = impl_impl_source;
+ let assoc_item_id = obligation.predicate.item_def_id;
+ let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
+
+ let param_env = obligation.param_env;
+ let Ok(assoc_ty) = assoc_def(selcx, impl_def_id, assoc_item_id) else {
+ return Progress { term: tcx.ty_error().into(), obligations: nested };
+ };
+
+ if !assoc_ty.item.defaultness(tcx).has_value() {
+ // This means that the impl is missing a definition for the
+ // associated type. This error will be reported by the type
+ // checker method `check_impl_items_against_trait`, so here we
+ // just return Error.
+ debug!(
+ "confirm_impl_candidate: no associated type {:?} for {:?}",
+ assoc_ty.item.name, obligation.predicate
+ );
+ return Progress { term: tcx.ty_error().into(), obligations: nested };
+ }
+ // If we're trying to normalize `<Vec<u32> as X>::A<S>` using
+ //`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
+ //
+ // * `obligation.predicate.substs` is `[Vec<u32>, S]`
+ // * `substs` is `[u32]`
+ // * `substs` ends up as `[u32, S]`
+ let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
+ let substs =
+ translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
+ let ty = tcx.bound_type_of(assoc_ty.item.def_id);
+ let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
+ let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
+ let identity_substs =
+ crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
+ let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
+ let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
+ ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
+ } else {
+ ty.map_bound(|ty| ty.into())
+ };
+ if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
+ let err = tcx.ty_error_with_message(
+ obligation.cause.span,
+ "impl item and trait item have different parameter counts",
+ );
+ Progress { term: err.into(), obligations: nested }
+ } else {
+ assoc_ty_own_obligations(selcx, obligation, &mut nested);
+ Progress { term: term.subst(tcx, substs), obligations: nested }
+ }
+}
+
+// Get obligations corresponding to the predicates from the where-clause of the
+// associated type itself.
+// Note: `feature(generic_associated_types)` is required to write such
+// predicates, even for non-generic associated types.
+fn assoc_ty_own_obligations<'cx, 'tcx>(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ obligation: &ProjectionTyObligation<'tcx>,
+ nested: &mut Vec<PredicateObligation<'tcx>>,
+) {
+ let tcx = selcx.tcx();
+ for predicate in tcx
+ .predicates_of(obligation.predicate.item_def_id)
+ .instantiate_own(tcx, obligation.predicate.substs)
+ .predicates
+ {
+ let normalized = normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ predicate,
+ nested,
+ );
+ nested.push(Obligation::with_depth(
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ normalized,
+ ));
+ }
+}
+
+/// Locate the definition of an associated type in the specialization hierarchy,
+/// starting from the given impl.
+///
+/// Based on the "projection mode", this lookup may in fact only examine the
+/// topmost impl. See the comments for `Reveal` for more details.
+fn assoc_def(
+ selcx: &SelectionContext<'_, '_>,
+ impl_def_id: DefId,
+ assoc_def_id: DefId,
+) -> Result<specialization_graph::LeafDef, ErrorGuaranteed> {
+ let tcx = selcx.tcx();
+ let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
+ let trait_def = tcx.trait_def(trait_def_id);
+
+ // This function may be called while we are still building the
+ // specialization graph that is queried below (via TraitDef::ancestors()),
+ // so, in order to avoid unnecessary infinite recursion, we manually look
+ // for the associated item at the given impl.
+ // If there is no such item in that impl, this function will fail with a
+ // cycle error if the specialization graph is currently being built.
+ if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_def_id) {
+ let item = tcx.associated_item(impl_item_id);
+ let impl_node = specialization_graph::Node::Impl(impl_def_id);
+ return Ok(specialization_graph::LeafDef {
+ item: *item,
+ defining_node: impl_node,
+ finalizing_node: if item.defaultness(tcx).is_default() {
+ None
+ } else {
+ Some(impl_node)
+ },
+ });
+ }
+
+ let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
+ if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_def_id) {
+ Ok(assoc_item)
+ } else {
+ // This is saying that neither the trait nor
+ // the impl contain a definition for this
+ // associated type. Normally this situation
+ // could only arise through a compiler bug --
+ // if the user wrote a bad item name, it
+ // should have failed in astconv.
+ bug!(
+ "No associated type `{}` for {}",
+ tcx.item_name(assoc_def_id),
+ tcx.def_path_str(impl_def_id)
+ )
+ }
+}
+
+pub(crate) trait ProjectionCacheKeyExt<'cx, 'tcx>: Sized {
+ fn from_poly_projection_predicate(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ predicate: ty::PolyProjectionPredicate<'tcx>,
+ ) -> Option<Self>;
+}
+
+impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> {
+ fn from_poly_projection_predicate(
+ selcx: &mut SelectionContext<'cx, 'tcx>,
+ predicate: ty::PolyProjectionPredicate<'tcx>,
+ ) -> Option<Self> {
+ let infcx = selcx.infcx();
+ // We don't do cross-snapshot caching of obligations with escaping regions,
+ // so there's no cache key to use
+ predicate.no_bound_vars().map(|predicate| {
+ ProjectionCacheKey::new(
+ // We don't attempt to match up with a specific type-variable state
+ // from a specific call to `opt_normalize_projection_type` - if
+ // there's no precise match, the original cache entry is "stranded"
+ // anyway.
+ infcx.resolve_vars_if_possible(predicate.projection_ty),
+ )
+ })
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
new file mode 100644
index 000000000..aad3c37f8
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -0,0 +1,73 @@
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
+
+/// This returns true if the type `ty` is "trivial" for
+/// dropck-outlives -- that is, if it doesn't require any types to
+/// outlive. This is similar but not *quite* the same as the
+/// `needs_drop` test in the compiler already -- that is, for every
+/// type T for which this function return true, needs-drop would
+/// return `false`. But the reverse does not hold: in particular,
+/// `needs_drop` returns false for `PhantomData`, but it is not
+/// trivial for dropck-outlives.
+///
+/// Note also that `needs_drop` requires a "global" type (i.e., one
+/// with erased regions), but this function does not.
+///
+// FIXME(@lcnr): remove this module and move this function somewhere else.
+pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
+ match ty.kind() {
+ // None of these types have a destructor and hence they do not
+ // require anything in particular to outlive the dtor's
+ // execution.
+ ty::Infer(ty::FreshIntTy(_))
+ | ty::Infer(ty::FreshFloatTy(_))
+ | ty::Bool
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Never
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Char
+ | ty::GeneratorWitness(..)
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::Str
+ | ty::Foreign(..)
+ | ty::Error(_) => true,
+
+ // [T; N] and [T] have same properties as T.
+ ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
+
+ // (T1..Tn) and closures have same properties as T1..Tn --
+ // check if *all* of them are trivial.
+ ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
+ ty::Closure(_, ref substs) => {
+ trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
+ }
+
+ ty::Adt(def, _) => {
+ if Some(def.did()) == tcx.lang_items().manually_drop() {
+ // `ManuallyDrop` never has a dtor.
+ true
+ } else {
+ // Other types might. Moreover, PhantomData doesn't
+ // have a dtor, but it is considered to own its
+ // content, so it is non-trivial. Unions can have `impl Drop`,
+ // and hence are non-trivial as well.
+ false
+ }
+ }
+
+ // The following *might* require a destructor: needs deeper inspection.
+ ty::Dynamic(..)
+ | ty::Projection(..)
+ | ty::Param(_)
+ | ty::Opaque(..)
+ | ty::Placeholder(..)
+ | ty::Infer(_)
+ | ty::Bound(..)
+ | ty::Generator(..) => false,
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
new file mode 100644
index 000000000..32669e23d
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -0,0 +1,118 @@
+use rustc_middle::ty;
+
+use crate::infer::canonical::OriginalQueryValues;
+use crate::infer::InferCtxt;
+use crate::traits::{
+ EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode,
+};
+
+pub trait InferCtxtExt<'tcx> {
+ fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool;
+
+ fn predicate_must_hold_considering_regions(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> bool;
+
+ fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool;
+
+ fn evaluate_obligation(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError>;
+
+ // Helper function that canonicalizes and runs the query. If an
+ // overflow results, we re-run it in the local context so we can
+ // report a nice error.
+ /*crate*/
+ fn evaluate_obligation_no_overflow(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> EvaluationResult;
+}
+
+impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
+ /// Evaluates whether the predicate can be satisfied (by any means)
+ /// in the given `ParamEnv`.
+ fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
+ self.evaluate_obligation_no_overflow(obligation).may_apply()
+ }
+
+ /// Evaluates whether the predicate can be satisfied in the given
+ /// `ParamEnv`, and returns `false` if not certain. However, this is
+ /// not entirely accurate if inference variables are involved.
+ ///
+ /// This version may conservatively fail when outlives obligations
+ /// are required.
+ fn predicate_must_hold_considering_regions(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> bool {
+ self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions()
+ }
+
+ /// Evaluates whether the predicate can be satisfied in the given
+ /// `ParamEnv`, and returns `false` if not certain. However, this is
+ /// not entirely accurate if inference variables are involved.
+ ///
+ /// This version ignores all outlives constraints.
+ fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool {
+ self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
+ }
+
+ /// Evaluate a given predicate, capturing overflow and propagating it back.
+ fn evaluate_obligation(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ let mut _orig_values = OriginalQueryValues::default();
+
+ let param_env = match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ // we ignore the value set to it.
+ let mut _constness = pred.constness;
+ obligation
+ .param_env
+ .with_constness(_constness.and(obligation.param_env.constness()))
+ }
+ // constness has no effect on the given predicate.
+ _ => obligation.param_env.without_const(),
+ };
+
+ let c_pred = self
+ .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
+ // Run canonical query. If overflow occurs, rerun from scratch but this time
+ // in standard trait query mode so that overflow is handled appropriately
+ // within `SelectionContext`.
+ self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+ }
+
+ // Helper function that canonicalizes and runs the query. If an
+ // overflow results, we re-run it in the local context so we can
+ // report a nice error.
+ fn evaluate_obligation_no_overflow(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> EvaluationResult {
+ match self.evaluate_obligation(obligation) {
+ Ok(result) => result,
+ Err(OverflowError::Canonical) => {
+ let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
+ selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
+ OverflowError::Canonical => {
+ span_bug!(
+ obligation.cause.span,
+ "Overflow should be caught earlier in standard query mode: {:?}, {:?}",
+ obligation,
+ r,
+ )
+ }
+ OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr,
+ OverflowError::Error(_) => EvaluationResult::EvaluatedToErr,
+ })
+ }
+ Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr,
+ Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs b/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs
new file mode 100644
index 000000000..3c0ebec93
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs
@@ -0,0 +1,3 @@
+pub use rustc_middle::traits::query::{
+ CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult,
+};
diff --git a/compiler/rustc_trait_selection/src/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs
new file mode 100644
index 000000000..ef3493678
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/mod.rs
@@ -0,0 +1,14 @@
+//! Experimental types for the trait query interface. The methods
+//! defined in this module are all based on **canonicalization**,
+//! which makes a canonical query by replacing unbound inference
+//! variables and regions, so that results can be reused more broadly.
+//! The providers for the queries defined here can be found in
+//! `rustc_traits`.
+
+pub mod dropck_outlives;
+pub mod evaluate_obligation;
+pub mod method_autoderef;
+pub mod normalize;
+pub mod type_op;
+
+pub use rustc_middle::traits::query::*;
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
new file mode 100644
index 000000000..449d7a7b4
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -0,0 +1,354 @@
+//! Code for the 'normalization' query. This consists of a wrapper
+//! which folds deeply, invoking the underlying
+//! `normalize_projection_ty` query when it encounters projections.
+
+use crate::infer::at::At;
+use crate::infer::canonical::OriginalQueryValues;
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::project::needs_normalization;
+use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
+use rustc_data_structures::sso::SsoHashMap;
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_infer::traits::Normalized;
+use rustc_middle::mir;
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+
+use std::ops::ControlFlow;
+
+use super::NoSolution;
+
+pub use rustc_middle::traits::query::NormalizationResult;
+
+pub trait AtExt<'tcx> {
+ fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
+ where
+ T: TypeFoldable<'tcx>;
+}
+
+impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
+ /// Normalize `value` in the context of the inference context,
+ /// yielding a resulting type, or an error if `value` cannot be
+ /// normalized. If you don't care about regions, you should prefer
+ /// `normalize_erasing_regions`, which is more efficient.
+ ///
+ /// If the normalization succeeds and is unambiguous, returns back
+ /// the normalized value along with various outlives relations (in
+ /// the form of obligations that must be discharged).
+ ///
+ /// N.B., this will *eventually* be the main means of
+ /// normalizing, but for now should be used only when we actually
+ /// know that normalization will succeed, since error reporting
+ /// and other details are still "under development".
+ fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ debug!(
+ "normalize::<{}>(value={:?}, param_env={:?})",
+ std::any::type_name::<T>(),
+ value,
+ self.param_env,
+ );
+ if !needs_normalization(&value, self.param_env.reveal()) {
+ return Ok(Normalized { value, obligations: vec![] });
+ }
+
+ let mut normalizer = QueryNormalizer {
+ infcx: self.infcx,
+ cause: self.cause,
+ param_env: self.param_env,
+ obligations: vec![],
+ cache: SsoHashMap::new(),
+ anon_depth: 0,
+ universes: vec![],
+ };
+
+ // This is actually a consequence by the way `normalize_erasing_regions` works currently.
+ // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
+ // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
+ // with trying to normalize with escaping bound vars.
+ //
+ // Here, we just add the universes that we *would* have created had we passed through the binders.
+ //
+ // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
+ // The rest of the code is already set up to be lazy about replacing bound vars,
+ // and only when we actually have to normalize.
+ if value.has_escaping_bound_vars() {
+ let mut max_visitor =
+ MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
+ value.visit_with(&mut max_visitor);
+ if max_visitor.escaping > 0 {
+ normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
+ }
+ }
+ let result = value.try_fold_with(&mut normalizer);
+ info!(
+ "normalize::<{}>: result={:?} with {} obligations",
+ std::any::type_name::<T>(),
+ result,
+ normalizer.obligations.len(),
+ );
+ debug!(
+ "normalize::<{}>: obligations={:?}",
+ std::any::type_name::<T>(),
+ normalizer.obligations,
+ );
+ result.map(|value| Normalized { value, obligations: normalizer.obligations })
+ }
+}
+
+// Visitor to find the maximum escaping bound var
+struct MaxEscapingBoundVarVisitor {
+ // The index which would count as escaping
+ outer_index: ty::DebruijnIndex,
+ escaping: usize,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
+ fn visit_binder<T: TypeVisitable<'tcx>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ self.outer_index.shift_in(1);
+ let result = t.super_visit_with(self);
+ self.outer_index.shift_out(1);
+ result
+ }
+
+ #[inline]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if t.outer_exclusive_binder() > self.outer_index {
+ self.escaping = self
+ .escaping
+ .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
+ }
+ ControlFlow::CONTINUE
+ }
+
+ #[inline]
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ ty::ReLateBound(debruijn, _) if debruijn > self.outer_index => {
+ self.escaping =
+ self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
+ }
+ _ => {}
+ }
+ ControlFlow::CONTINUE
+ }
+
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match ct.kind() {
+ ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
+ self.escaping =
+ self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
+ ControlFlow::CONTINUE
+ }
+ _ => ct.super_visit_with(self),
+ }
+ }
+}
+
+struct QueryNormalizer<'cx, 'tcx> {
+ infcx: &'cx InferCtxt<'cx, 'tcx>,
+ cause: &'cx ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ obligations: Vec<PredicateObligation<'tcx>>,
+ cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
+ anon_depth: usize,
+ universes: Vec<Option<ty::UniverseIndex>>,
+}
+
+impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
+ type Error = NoSolution;
+
+ fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn try_fold_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: ty::Binder<'tcx, T>,
+ ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
+ self.universes.push(None);
+ let t = t.try_super_fold_with(self);
+ self.universes.pop();
+ t
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+ if !needs_normalization(&ty, self.param_env.reveal()) {
+ return Ok(ty);
+ }
+
+ if let Some(ty) = self.cache.get(&ty) {
+ return Ok(*ty);
+ }
+
+ // See note in `rustc_trait_selection::traits::project` about why we
+ // wait to fold the substs.
+
+ // Wrap this in a closure so we don't accidentally return from the outer function
+ let res = (|| match *ty.kind() {
+ // This is really important. While we *can* handle this, this has
+ // severe performance implications for large opaque types with
+ // late-bound regions. See `issue-88862` benchmark.
+ ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
+ // Only normalize `impl Trait` outside of type inference, usually in codegen.
+ match self.param_env.reveal() {
+ Reveal::UserFacing => ty.try_super_fold_with(self),
+
+ Reveal::All => {
+ let substs = substs.try_fold_with(self)?;
+ let recursion_limit = self.tcx().recursion_limit();
+ if !recursion_limit.value_within_limit(self.anon_depth) {
+ let obligation = Obligation::with_depth(
+ self.cause.clone(),
+ recursion_limit.0,
+ self.param_env,
+ ty,
+ );
+ self.infcx.report_overflow_error(&obligation, true);
+ }
+
+ let generic_ty = self.tcx().bound_type_of(def_id);
+ let concrete_ty = generic_ty.subst(self.tcx(), substs);
+ self.anon_depth += 1;
+ if concrete_ty == ty {
+ bug!(
+ "infinite recursion generic_ty: {:#?}, substs: {:#?}, \
+ concrete_ty: {:#?}, ty: {:#?}",
+ generic_ty,
+ substs,
+ concrete_ty,
+ ty
+ );
+ }
+ let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty));
+ self.anon_depth -= 1;
+ folded_ty
+ }
+ }
+ }
+
+ ty::Projection(data) if !data.has_escaping_bound_vars() => {
+ // This branch is just an optimization: when we don't have escaping bound vars,
+ // we don't need to replace them with placeholders (see branch below).
+
+ let tcx = self.infcx.tcx;
+ let data = data.try_fold_with(self)?;
+
+ let mut orig_values = OriginalQueryValues::default();
+ // HACK(matthewjasper) `'static` is special-cased in selection,
+ // so we cannot canonicalize it.
+ let c_data = self
+ .infcx
+ .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
+ debug!("QueryNormalizer: c_data = {:#?}", c_data);
+ debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+ }
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(result.normalized_ty)
+ }
+
+ ty::Projection(data) => {
+ // See note in `rustc_trait_selection::traits::project`
+
+ let tcx = self.infcx.tcx;
+ let infcx = self.infcx;
+ let (data, mapped_regions, mapped_types, mapped_consts) =
+ crate::traits::project::BoundVarReplacer::replace_bound_vars(
+ infcx,
+ &mut self.universes,
+ data,
+ );
+ let data = data.try_fold_with(self)?;
+
+ let mut orig_values = OriginalQueryValues::default();
+ // HACK(matthewjasper) `'static` is special-cased in selection,
+ // so we cannot canonicalize it.
+ let c_data = self
+ .infcx
+ .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
+ debug!("QueryNormalizer: c_data = {:#?}", c_data);
+ debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
+ let result = tcx.normalize_projection_ty(c_data)?;
+ // We don't expect ambiguity.
+ if result.is_ambiguous() {
+ bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
+ }
+ let InferOk { value: result, obligations } =
+ self.infcx.instantiate_query_response_and_region_obligations(
+ self.cause,
+ self.param_env,
+ &orig_values,
+ result,
+ )?;
+ debug!("QueryNormalizer: result = {:#?}", result);
+ debug!("QueryNormalizer: obligations = {:#?}", obligations);
+ self.obligations.extend(obligations);
+ Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ result.normalized_ty,
+ ))
+ }
+
+ _ => ty.try_super_fold_with(self),
+ })()?;
+ self.cache.insert(ty, res);
+ Ok(res)
+ }
+
+ fn try_fold_const(
+ &mut self,
+ constant: ty::Const<'tcx>,
+ ) -> Result<ty::Const<'tcx>, Self::Error> {
+ let constant = constant.try_super_fold_with(self)?;
+ Ok(constant.eval(self.infcx.tcx, self.param_env))
+ }
+
+ fn try_fold_mir_const(
+ &mut self,
+ constant: mir::ConstantKind<'tcx>,
+ ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
+ Ok(match constant {
+ mir::ConstantKind::Ty(c) => {
+ let const_folded = c.try_super_fold_with(self)?;
+ match const_folded.kind() {
+ ty::ConstKind::Value(valtree) => {
+ let tcx = self.infcx.tcx;
+ let ty = const_folded.ty();
+ let const_val = tcx.valtree_to_const_val((ty, valtree));
+ debug!(?ty, ?valtree, ?const_val);
+
+ mir::ConstantKind::Val(const_val, ty)
+ }
+ _ => mir::ConstantKind::Ty(const_folded),
+ }
+ }
+ mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
+ })
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
new file mode 100644
index 000000000..86b015767
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -0,0 +1,23 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::Fallible;
+use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+
+pub use rustc_middle::traits::query::type_op::AscribeUserType;
+
+impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
+ type QueryResponse = ();
+
+ fn try_fast_path(
+ _tcx: TyCtxt<'tcx>,
+ _key: &ParamEnvAnd<'tcx, Self>,
+ ) -> Option<Self::QueryResponse> {
+ None
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ tcx.type_op_ascribe_user_type(canonicalized)
+ }
+}
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
new file mode 100644
index 000000000..c99564936
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -0,0 +1,117 @@
+use crate::infer::canonical::query_response;
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::engine::TraitEngineExt as _;
+use crate::traits::query::type_op::TypeOpOutput;
+use crate::traits::query::Fallible;
+use crate::traits::TraitEngine;
+use rustc_infer::infer::region_constraints::RegionConstraintData;
+use rustc_infer::traits::TraitEngineExt as _;
+use rustc_span::source_map::DUMMY_SP;
+
+use std::fmt;
+
+pub struct CustomTypeOp<F, G> {
+ closure: F,
+ description: G,
+}
+
+impl<F, G> CustomTypeOp<F, G> {
+ pub fn new<'tcx, R>(closure: F, description: G) -> Self
+ where
+ F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
+ G: Fn() -> String,
+ {
+ CustomTypeOp { closure, description }
+ }
+}
+
+impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
+where
+ F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
+ G: Fn() -> String,
+{
+ type Output = R;
+ /// We can't do any custom error reporting for `CustomTypeOp`, so
+ /// we can use `!` to enforce that the implementation never provides it.
+ type ErrorInfo = !;
+
+ /// Processes the operation and all resulting obligations,
+ /// returning the final result along with any region constraints
+ /// (they will be given over to the NLL region solver).
+ fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ if cfg!(debug_assertions) {
+ info!("fully_perform({:?})", self);
+ }
+
+ Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0)
+ }
+}
+
+impl<F, G> fmt::Debug for CustomTypeOp<F, G>
+where
+ G: Fn() -> String,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", (self.description)())
+ }
+}
+
+/// Executes `op` and then scrapes out all the "old style" region
+/// constraints that result, creating query-region-constraints.
+pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
+ infcx: &InferCtxt<'_, 'tcx>,
+ op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
+) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+
+ // During NLL, we expect that nobody will register region
+ // obligations **except** as part of a custom type op (and, at the
+ // end of each custom type op, we scrape out the region
+ // obligations that resulted). So this vector should be empty on
+ // entry.
+ let pre_obligations = infcx.take_registered_region_obligations();
+ assert!(
+ pre_obligations.is_empty(),
+ "scrape_region_constraints: incoming region obligations = {:#?}",
+ pre_obligations,
+ );
+
+ let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ infcx.tcx.sess.diagnostic().delay_span_bug(
+ DUMMY_SP,
+ &format!("errors selecting obligation during MIR typeck: {:?}", errors),
+ );
+ }
+
+ let region_obligations = infcx.take_registered_region_obligations();
+
+ let region_constraint_data = infcx.take_and_reset_region_constraints();
+
+ let region_constraints = query_response::make_query_region_constraints(
+ infcx.tcx,
+ region_obligations
+ .iter()
+ .map(|r_o| (r_o.sup_type, r_o.sub_region))
+ .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)),
+ &region_constraint_data,
+ );
+
+ if region_constraints.is_empty() {
+ Ok((
+ TypeOpOutput { output: value, constraints: None, error_info: None },
+ region_constraint_data,
+ ))
+ } else {
+ Ok((
+ TypeOpOutput {
+ output: value,
+ constraints: Some(infcx.tcx.arena.alloc(region_constraints)),
+ error_info: None,
+ },
+ region_constraint_data,
+ ))
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
new file mode 100644
index 000000000..490114aac
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
@@ -0,0 +1,23 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::Fallible;
+use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+
+pub use rustc_middle::traits::query::type_op::Eq;
+
+impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
+ type QueryResponse = ();
+
+ fn try_fast_path(
+ _tcx: TyCtxt<'tcx>,
+ key: &ParamEnvAnd<'tcx, Eq<'tcx>>,
+ ) -> Option<Self::QueryResponse> {
+ if key.value.a == key.value.b { Some(()) } else { None }
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ tcx.type_op_eq(canonicalized)
+ }
+}
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
new file mode 100644
index 000000000..2a3319f0f
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -0,0 +1,42 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::Fallible;
+use rustc_infer::traits::query::OutlivesBound;
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct ImpliedOutlivesBounds<'tcx> {
+ pub ty: Ty<'tcx>,
+}
+
+impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
+ type QueryResponse = Vec<OutlivesBound<'tcx>>;
+
+ fn try_fast_path(
+ _tcx: TyCtxt<'tcx>,
+ key: &ParamEnvAnd<'tcx, Self>,
+ ) -> Option<Self::QueryResponse> {
+ // Don't go into the query for things that can't possibly have lifetimes.
+ match key.value.ty.kind() {
+ ty::Tuple(elems) if elems.is_empty() => Some(vec![]),
+ ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
+ Some(vec![])
+ }
+ _ => None,
+ }
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+ // FIXME this `unchecked_map` is only necessary because the
+ // query is defined as taking a `ParamEnvAnd<Ty>`; it should
+ // take an `ImpliedOutlivesBounds` instead
+ let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
+ let ImpliedOutlivesBounds { ty } = value;
+ param_env.and(ty)
+ });
+
+ tcx.implied_outlives_bounds(canonicalized)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
new file mode 100644
index 000000000..578e1d00c
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -0,0 +1,168 @@
+use crate::infer::canonical::{
+ Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints,
+};
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::query::Fallible;
+use crate::traits::ObligationCause;
+use rustc_infer::infer::canonical::{Canonical, Certainty};
+use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::PredicateObligations;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+use std::fmt;
+
+pub mod ascribe_user_type;
+pub mod custom;
+pub mod eq;
+pub mod implied_outlives_bounds;
+pub mod normalize;
+pub mod outlives;
+pub mod prove_predicate;
+pub mod subtype;
+
+pub use rustc_middle::traits::query::type_op::*;
+
+/// "Type ops" are used in NLL to perform some particular action and
+/// extract out the resulting region constraints (or an error if it
+/// cannot be completed).
+pub trait TypeOp<'tcx>: Sized + fmt::Debug {
+ type Output;
+ type ErrorInfo;
+
+ /// Processes the operation and all resulting obligations,
+ /// returning the final result along with any region constraints
+ /// (they will be given over to the NLL region solver).
+ fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
+}
+
+/// The output from performing a type op
+pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
+ /// The output from the type op.
+ pub output: Op::Output,
+ /// Any region constraints from performing the type op.
+ pub constraints: Option<&'tcx QueryRegionConstraints<'tcx>>,
+ /// Used for error reporting to be able to rerun the query
+ pub error_info: Option<Op::ErrorInfo>,
+}
+
+/// "Query type ops" are type ops that are implemented using a
+/// [canonical query][c]. The `Self` type here contains the kernel of
+/// information needed to do the operation -- `TypeOp` is actually
+/// implemented for `ParamEnvAnd<Self>`, since we always need to bring
+/// along a parameter environment as well. For query type-ops, we will
+/// first canonicalize the key and then invoke the query on the tcx,
+/// which produces the resulting query region constraints.
+///
+/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
+pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
+ type QueryResponse: TypeFoldable<'tcx>;
+
+ /// Give query the option for a simple fast path that never
+ /// actually hits the tcx cache lookup etc. Return `Some(r)` with
+ /// a final result or `None` to do the full path.
+ fn try_fast_path(
+ tcx: TyCtxt<'tcx>,
+ key: &ParamEnvAnd<'tcx, Self>,
+ ) -> Option<Self::QueryResponse>;
+
+ /// Performs the actual query with the canonicalized key -- the
+ /// real work happens here. This method is not given an `infcx`
+ /// because it shouldn't need one -- and if it had access to one,
+ /// it might do things like invoke `sub_regions`, which would be
+ /// bad, because it would create subregion relationships that are
+ /// not captured in the return value.
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>;
+
+ fn fully_perform_into(
+ query_key: ParamEnvAnd<'tcx, Self>,
+ infcx: &InferCtxt<'_, 'tcx>,
+ output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
+ ) -> Fallible<(
+ Self::QueryResponse,
+ Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
+ PredicateObligations<'tcx>,
+ Certainty,
+ )> {
+ if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
+ return Ok((result, None, vec![], Certainty::Proven));
+ }
+
+ // FIXME(#33684) -- We need to use
+ // `canonicalize_query_keep_static` here because of things
+ // like the subtype query, which go awry around
+ // `'static` otherwise.
+ let mut canonical_var_values = OriginalQueryValues::default();
+ let old_param_env = query_key.param_env;
+ let canonical_self =
+ infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values);
+ let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;
+
+ let InferOk { value, obligations } = infcx
+ .instantiate_nll_query_response_and_region_obligations(
+ &ObligationCause::dummy(),
+ old_param_env,
+ &canonical_var_values,
+ canonical_result,
+ output_query_region_constraints,
+ )?;
+
+ Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
+ }
+}
+
+impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
+where
+ Q: QueryTypeOp<'tcx>,
+{
+ type Output = Q::QueryResponse;
+ type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
+
+ fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ let mut region_constraints = QueryRegionConstraints::default();
+ let (output, error_info, mut obligations, _) =
+ Q::fully_perform_into(self, infcx, &mut region_constraints)?;
+
+ // Typically, instantiating NLL query results does not
+ // create obligations. However, in some cases there
+ // are unresolved type variables, and unify them *can*
+ // create obligations. In that case, we have to go
+ // fulfill them. We do this via a (recursive) query.
+ while !obligations.is_empty() {
+ trace!("{:#?}", obligations);
+ let mut progress = false;
+ for obligation in std::mem::take(&mut obligations) {
+ let obligation = infcx.resolve_vars_if_possible(obligation);
+ match ProvePredicate::fully_perform_into(
+ obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
+ infcx,
+ &mut region_constraints,
+ ) {
+ Ok(((), _, new, certainty)) => {
+ obligations.extend(new);
+ progress = true;
+ if let Certainty::Ambiguous = certainty {
+ obligations.push(obligation);
+ }
+ }
+ Err(_) => obligations.push(obligation),
+ }
+ }
+ if !progress {
+ return Err(NoSolution);
+ }
+ }
+
+ Ok(TypeOpOutput {
+ output,
+ constraints: if region_constraints.is_empty() {
+ None
+ } else {
+ Some(infcx.tcx.arena.alloc(region_constraints))
+ },
+ error_info,
+ })
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
new file mode 100644
index 000000000..e92ca7325
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -0,0 +1,68 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::Fallible;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
+use std::fmt;
+
+pub use rustc_middle::traits::query::type_op::Normalize;
+
+impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
+where
+ T: Normalizable<'tcx> + 'tcx,
+{
+ type QueryResponse = T;
+
+ fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> {
+ if !key.value.value.has_projections() { Some(key.value.value) } else { None }
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+ T::type_op_method(tcx, canonicalized)
+ }
+}
+
+pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy {
+ fn type_op_method(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>;
+}
+
+impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
+ fn type_op_method(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ tcx.type_op_normalize_ty(canonicalized)
+ }
+}
+
+impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
+ fn type_op_method(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ tcx.type_op_normalize_predicate(canonicalized)
+ }
+}
+
+impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
+ fn type_op_method(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ tcx.type_op_normalize_poly_fn_sig(canonicalized)
+ }
+}
+
+impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
+ fn type_op_method(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> {
+ tcx.type_op_normalize_fn_sig(canonicalized)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
new file mode 100644
index 000000000..b63382429
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -0,0 +1,55 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult};
+use crate::traits::query::Fallible;
+use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
+
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
+pub struct DropckOutlives<'tcx> {
+ dropped_ty: Ty<'tcx>,
+}
+
+impl<'tcx> DropckOutlives<'tcx> {
+ pub fn new(dropped_ty: Ty<'tcx>) -> Self {
+ DropckOutlives { dropped_ty }
+ }
+}
+
+impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
+ type QueryResponse = DropckOutlivesResult<'tcx>;
+
+ fn try_fast_path(
+ tcx: TyCtxt<'tcx>,
+ key: &ParamEnvAnd<'tcx, Self>,
+ ) -> Option<Self::QueryResponse> {
+ if trivial_dropck_outlives(tcx, key.value.dropped_ty) {
+ Some(DropckOutlivesResult::default())
+ } else {
+ None
+ }
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
+ // Subtle: note that we are not invoking
+ // `infcx.at(...).dropck_outlives(...)` here, but rather the
+ // underlying `dropck_outlives` query. This same underlying
+ // query is also used by the
+ // `infcx.at(...).dropck_outlives(...)` fn. Avoiding the
+ // wrapper means we don't need an infcx in this code, which is
+ // good because the interface doesn't give us one (so that we
+ // know we are not registering any subregion relations or
+ // other things).
+
+ // FIXME convert to the type expected by the `dropck_outlives`
+ // query. This should eventually be fixed by changing the
+ // *underlying query*.
+ let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
+ let DropckOutlives { dropped_ty } = value;
+ param_env.and(dropped_ty)
+ });
+
+ tcx.dropck_outlives(canonicalized)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
new file mode 100644
index 000000000..081308ac7
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -0,0 +1,43 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::Fallible;
+use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
+
+pub use rustc_middle::traits::query::type_op::ProvePredicate;
+
+impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
+ type QueryResponse = ();
+
+ fn try_fast_path(
+ tcx: TyCtxt<'tcx>,
+ key: &ParamEnvAnd<'tcx, Self>,
+ ) -> Option<Self::QueryResponse> {
+ // Proving Sized, very often on "obviously sized" types like
+ // `&T`, accounts for about 60% percentage of the predicates
+ // we have to prove. No need to canonicalize and all that for
+ // such cases.
+ if let ty::PredicateKind::Trait(trait_ref) = key.value.predicate.kind().skip_binder() {
+ if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
+ if trait_ref.def_id() == sized_def_id {
+ if trait_ref.self_ty().is_trivially_sized(tcx) {
+ return Some(());
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ mut canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ match canonicalized.value.value.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ canonicalized.value.param_env.remap_constness_with(pred.constness);
+ }
+ _ => canonicalized.value.param_env = canonicalized.value.param_env.without_const(),
+ }
+ tcx.type_op_prove_predicate(canonicalized)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
new file mode 100644
index 000000000..57290b669
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
@@ -0,0 +1,20 @@
+use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
+use crate::traits::query::Fallible;
+use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+
+pub use rustc_middle::traits::query::type_op::Subtype;
+
+impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
+ type QueryResponse = ();
+
+ fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> {
+ if key.value.sub == key.value.sup { Some(()) } else { None }
+ }
+
+ fn perform_query(
+ tcx: TyCtxt<'tcx>,
+ canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> {
+ tcx.type_op_subtype(canonicalized)
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs
new file mode 100644
index 000000000..8148e2b78
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/relationships.rs
@@ -0,0 +1,58 @@
+use crate::infer::InferCtxt;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{ObligationCause, PredicateObligation};
+use rustc_infer::traits::TraitEngine;
+use rustc_middle::ty::{self, ToPredicate};
+
+pub(crate) fn update<'tcx, T>(
+ engine: &mut T,
+ infcx: &InferCtxt<'_, 'tcx>,
+ obligation: &PredicateObligation<'tcx>,
+) where
+ T: TraitEngine<'tcx>,
+{
+ // (*) binder skipped
+ if let ty::PredicateKind::Trait(tpred) = obligation.predicate.kind().skip_binder()
+ && let Some(ty) = infcx.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| infcx.root_var(t))
+ && infcx.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
+ {
+ let new_self_ty = infcx.tcx.types.unit;
+
+ let trait_ref = ty::TraitRef {
+ substs: infcx.tcx.mk_substs_trait(new_self_ty, &tpred.trait_ref.substs[1..]),
+ ..tpred.trait_ref
+ };
+
+ // Then construct a new obligation with Self = () added
+ // to the ParamEnv, and see if it holds.
+ let o = rustc_infer::traits::Obligation::new(
+ ObligationCause::dummy(),
+ obligation.param_env,
+ obligation
+ .predicate
+ .kind()
+ .rebind(
+ // (*) binder moved here
+ ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: tpred.constness,
+ polarity: tpred.polarity,
+ })
+ )
+ .to_predicate(infcx.tcx),
+ );
+ // Don't report overflow errors. Otherwise equivalent to may_hold.
+ if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) && result.may_apply() {
+ engine.relationships().entry(ty).or_default().self_in_trait = true;
+ }
+ }
+
+ if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
+ // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
+ // we need to make it into one.
+ if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
+ debug!("relationship: {:?}.output = true", vid);
+ engine.relationships().entry(vid).or_default().output = true;
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
new file mode 100644
index 000000000..a60ce0f34
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -0,0 +1,1009 @@
+//! Candidate assembly.
+//!
+//! The selection process begins by examining all in-scope impls,
+//! caller obligations, and so forth and assembling a list of
+//! candidates. See the [rustc dev guide] for more details.
+//!
+//! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
+use hir::LangItem;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
+use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
+use rustc_target::spec::abi::Abi;
+
+use crate::traits;
+use crate::traits::coherence::Conflict;
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{util, SelectionResult};
+use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
+
+use super::BuiltinImplConditions;
+use super::IntercrateAmbiguityCause;
+use super::OverflowError;
+use super::SelectionCandidate::{self, *};
+use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack};
+
+impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+ #[instrument(level = "debug", skip(self))]
+ pub(super) fn candidate_from_obligation<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ // Watch out for overflow. This intentionally bypasses (and does
+ // not update) the cache.
+ self.check_recursion_limit(&stack.obligation, &stack.obligation)?;
+
+ // Check the cache. Note that we freshen the trait-ref
+ // separately rather than using `stack.fresh_trait_ref` --
+ // this is because we want the unbound variables to be
+ // replaced with fresh types starting from index 0.
+ let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate);
+ debug!(?cache_fresh_trait_pred);
+ debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
+
+ if let Some(c) =
+ self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
+ {
+ debug!(candidate = ?c, "CACHE HIT");
+ return c;
+ }
+
+ // If no match, compute result and insert into cache.
+ //
+ // FIXME(nikomatsakis) -- this cache is not taking into
+ // account cycles that may have occurred in forming the
+ // candidate. I don't know of any specific problems that
+ // result but it seems awfully suspicious.
+ let (candidate, dep_node) =
+ self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
+
+ debug!(?candidate, "CACHE MISS");
+ self.insert_candidate_cache(
+ stack.obligation.param_env,
+ cache_fresh_trait_pred,
+ dep_node,
+ candidate.clone(),
+ );
+ candidate
+ }
+
+ fn candidate_from_obligation_no_cache<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ if let Some(conflict) = self.is_knowable(stack) {
+ debug!("coherence stage: not knowable");
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ let mut no_candidates_apply = true;
+
+ for c in candidate_set.vec.iter() {
+ if self.evaluate_candidate(stack, &c)?.may_apply() {
+ no_candidates_apply = false;
+ break;
+ }
+ }
+
+ if !candidate_set.ambiguous && no_candidates_apply {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let (trait_desc, self_desc) = with_no_trimmed_paths!({
+ let trait_desc = trait_ref.print_only_trait_path().to_string();
+ let self_desc = if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ };
+ (trait_desc, self_desc)
+ });
+ let cause = if let Conflict::Upstream = conflict {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+ } else {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ };
+ debug!(?cause, "evaluate_stack: pushing cause");
+ self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
+ }
+ }
+ }
+ return Ok(None);
+ }
+
+ let candidate_set = self.assemble_candidates(stack)?;
+
+ if candidate_set.ambiguous {
+ debug!("candidate set contains ambig");
+ return Ok(None);
+ }
+
+ let candidates = candidate_set.vec;
+
+ debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
+
+ // At this point, we know that each of the entries in the
+ // candidate set is *individually* applicable. Now we have to
+ // figure out if they contain mutual incompatibilities. This
+ // frequently arises if we have an unconstrained input type --
+ // for example, we are looking for `$0: Eq` where `$0` is some
+ // unconstrained type variable. In that case, we'll get a
+ // candidate which assumes $0 == int, one that assumes `$0 ==
+ // usize`, etc. This spells an ambiguity.
+
+ let mut candidates = self.filter_impls(candidates, stack.obligation);
+
+ // If there is more than one candidate, first winnow them down
+ // by considering extra conditions (nested obligations and so
+ // forth). We don't winnow if there is exactly one
+ // candidate. This is a relatively minor distinction but it
+ // can lead to better inference and error-reporting. An
+ // example would be if there was an impl:
+ //
+ // impl<T:Clone> Vec<T> { fn push_clone(...) { ... } }
+ //
+ // and we were to see some code `foo.push_clone()` where `boo`
+ // is a `Vec<Bar>` and `Bar` does not implement `Clone`. If
+ // we were to winnow, we'd wind up with zero candidates.
+ // Instead, we select the right impl now but report "`Bar` does
+ // not implement `Clone`".
+ if candidates.len() == 1 {
+ return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
+ }
+
+ // Winnow, but record the exact outcome of evaluation, which
+ // is needed for specialization. Propagate overflow if it occurs.
+ let mut candidates = candidates
+ .into_iter()
+ .map(|c| match self.evaluate_candidate(stack, &c) {
+ Ok(eval) if eval.may_apply() => {
+ Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval }))
+ }
+ Ok(_) => Ok(None),
+ Err(OverflowError::Canonical) => Err(Overflow(OverflowError::Canonical)),
+ Err(OverflowError::ErrorReporting) => Err(ErrorReporting),
+ Err(OverflowError::Error(e)) => Err(Overflow(OverflowError::Error(e))),
+ })
+ .flat_map(Result::transpose)
+ .collect::<Result<Vec<_>, _>>()?;
+
+ debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
+
+ let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
+
+ // If there are STILL multiple candidates, we can further
+ // reduce the list by dropping duplicates -- including
+ // resolving specializations.
+ if candidates.len() > 1 {
+ let mut i = 0;
+ while i < candidates.len() {
+ let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
+ self.candidate_should_be_dropped_in_favor_of(
+ &candidates[i],
+ &candidates[j],
+ needs_infer,
+ )
+ });
+ if is_dup {
+ debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
+ candidates.swap_remove(i);
+ } else {
+ debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
+ i += 1;
+
+ // If there are *STILL* multiple candidates, give up
+ // and report ambiguity.
+ if i > 1 {
+ debug!("multiple matches, ambig");
+ return Err(Ambiguous(
+ candidates
+ .into_iter()
+ .filter_map(|c| match c.candidate {
+ SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
+ _ => None,
+ })
+ .collect(),
+ ));
+ }
+ }
+ }
+ }
+
+ // If there are *NO* candidates, then there are no impls --
+ // that we know of, anyway. Note that in the case where there
+ // are unbound type variables within the obligation, it might
+ // be the case that you could still satisfy the obligation
+ // from another crate by instantiating the type variables with
+ // a type from another crate that does have an impl. This case
+ // is checked for in `evaluate_stack` (and hence users
+ // who might care about this case, like coherence, should use
+ // that function).
+ if candidates.is_empty() {
+ // If there's an error type, 'downgrade' our result from
+ // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid
+ // emitting additional spurious errors, since we're guaranteed
+ // to have emitted at least one.
+ if stack.obligation.predicate.references_error() {
+ debug!(?stack.obligation.predicate, "found error type in predicate, treating as ambiguous");
+ return Ok(None);
+ }
+ return Err(Unimplemented);
+ }
+
+ // Just one candidate left.
+ self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
+ }
+
+ #[instrument(skip(self, stack), level = "debug")]
+ pub(super) fn assemble_candidates<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> {
+ let TraitObligationStack { obligation, .. } = *stack;
+ let obligation = &Obligation {
+ param_env: obligation.param_env,
+ cause: obligation.cause.clone(),
+ recursion_depth: obligation.recursion_depth,
+ predicate: self.infcx().resolve_vars_if_possible(obligation.predicate),
+ };
+
+ if obligation.predicate.skip_binder().self_ty().is_ty_var() {
+ debug!(ty = ?obligation.predicate.skip_binder().self_ty(), "ambiguous inference var or opaque type");
+ // Self is a type variable (e.g., `_: AsRef<str>`).
+ //
+ // This is somewhat problematic, as the current scheme can't really
+ // handle it turning to be a projection. This does end up as truly
+ // ambiguous in most cases anyway.
+ //
+ // Take the fast path out - this also improves
+ // performance by preventing assemble_candidates_from_impls from
+ // matching every impl for this trait.
+ return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true });
+ }
+
+ 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.
+ if obligation.polarity() == ty::ImplPolarity::Negative {
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ } else {
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
+
+ // Other bounds. Consider both in-scope bounds from fn decl
+ // and applicable impls. There is a certain set of precedence rules here.
+ let def_id = obligation.predicate.def_id();
+ let lang_items = self.tcx().lang_items();
+
+ if lang_items.copy_trait() == Some(def_id) {
+ debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
+
+ // User-defined copy impls are permitted, but only for
+ // structs and enums.
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+
+ // For other types, we'll use the builtin rules.
+ let copy_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
+ } else if lang_items.discriminant_kind_trait() == Some(def_id) {
+ // `DiscriminantKind` is automatically implemented for every type.
+ candidates.vec.push(DiscriminantKindCandidate);
+ } else if lang_items.pointee_trait() == Some(def_id) {
+ // `Pointee` is automatically implemented for every type.
+ candidates.vec.push(PointeeCandidate);
+ } else if lang_items.sized_trait() == Some(def_id) {
+ // Sized is never implementable by end-users, it is
+ // always automatically computed.
+ let sized_conditions = self.sized_conditions(obligation);
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
+ } else if lang_items.unsize_trait() == Some(def_id) {
+ self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+ } else if lang_items.destruct_trait() == Some(def_id) {
+ self.assemble_const_destruct_candidates(obligation, &mut candidates);
+ } else if lang_items.transmute_trait() == Some(def_id) {
+ // User-defined transmutability impls are permitted.
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_for_transmutability(obligation, &mut candidates);
+ } else {
+ if lang_items.clone_trait() == Some(def_id) {
+ // Same builtin conditions as `Copy`, i.e., every type which has builtin support
+ // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
+ // types have builtin support for `Clone`.
+ let clone_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+ }
+
+ self.assemble_generator_candidates(obligation, &mut candidates);
+ self.assemble_closure_candidates(obligation, &mut candidates);
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+ }
+
+ self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
+ self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
+ // Auto implementations have lower priority, so we only
+ // consider triggering a default if there is no other impl that can apply.
+ if candidates.vec.is_empty() {
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ }
+ }
+ debug!("candidate list size: {}", candidates.vec.len());
+ Ok(candidates)
+ }
+
+ #[tracing::instrument(level = "debug", skip(self, candidates))]
+ fn assemble_candidates_from_projected_tys(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ // Before we go into the whole placeholder thing, just
+ // quickly check if the self-type is a projection at all.
+ match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
+ ty::Projection(_) | ty::Opaque(..) => {}
+ ty::Infer(ty::TyVar(_)) => {
+ span_bug!(
+ obligation.cause.span,
+ "Self=_ should have been handled by assemble_candidates"
+ );
+ }
+ _ => return,
+ }
+
+ let result = self
+ .infcx
+ .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation));
+
+ candidates.vec.extend(result.into_iter().map(ProjectionCandidate));
+ }
+
+ /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller
+ /// supplied to find out whether it is listed among them.
+ ///
+ /// Never affects the inference environment.
+ #[tracing::instrument(level = "debug", skip(self, stack, candidates))]
+ fn assemble_candidates_from_caller_bounds<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) -> Result<(), SelectionError<'tcx>> {
+ debug!(?stack.obligation);
+
+ let all_bounds = stack
+ .obligation
+ .param_env
+ .caller_bounds()
+ .iter()
+ .filter_map(|o| o.to_opt_poly_trait_pred());
+
+ // Micro-optimization: filter out predicates relating to different traits.
+ let matching_bounds =
+ all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
+
+ // Keep only those bounds which may apply, and propagate overflow if it occurs.
+ for bound in matching_bounds {
+ // FIXME(oli-obk): it is suspicious that we are dropping the constness and
+ // polarity here.
+ let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;
+ if wc.may_apply() {
+ candidates.vec.push(ParamCandidate(bound));
+ }
+ }
+
+ Ok(())
+ }
+
+ fn assemble_generator_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
+ return;
+ }
+
+ // Okay to skip binder because the substs on generator 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() {
+ ty::Generator(..) => {
+ debug!(?self_ty, ?obligation, "assemble_generator_candidates",);
+
+ candidates.vec.push(GeneratorCandidate);
+ }
+ ty::Infer(ty::TyVar(_)) => {
+ debug!("assemble_generator_candidates: ambiguous self-type");
+ candidates.ambiguous = true;
+ }
+ _ => {}
+ }
+ }
+
+ /// Checks for the artificial impl that the compiler will create for an obligation like `X :
+ /// FnMut<..>` where `X` is a closure type.
+ ///
+ /// Note: the type parameters on a closure candidate are modeled as *output* type
+ /// parameters and hence do not affect whether this trait is a match or not. They will be
+ /// unified during the confirmation step.
+ fn assemble_closure_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ let Some(kind) = self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) else {
+ return;
+ };
+
+ // Okay to skip binder because the substs on closure types never
+ // touch bound regions, they just capture the in-scope
+ // type/region parameters
+ match *obligation.self_ty().skip_binder().kind() {
+ ty::Closure(_, closure_substs) => {
+ debug!(?kind, ?obligation, "assemble_unboxed_candidates");
+ match self.infcx.closure_kind(closure_substs) {
+ Some(closure_kind) => {
+ debug!(?closure_kind, "assemble_unboxed_candidates");
+ if closure_kind.extends(kind) {
+ candidates.vec.push(ClosureCandidate);
+ }
+ }
+ None => {
+ debug!("assemble_unboxed_candidates: closure_kind not yet known");
+ candidates.vec.push(ClosureCandidate);
+ }
+ }
+ }
+ ty::Infer(ty::TyVar(_)) => {
+ debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
+ candidates.ambiguous = true;
+ }
+ _ => {}
+ }
+ }
+
+ /// Implements one of the `Fn()` family for a fn pointer.
+ fn assemble_fn_pointer_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ // We provide impl of all fn traits for fn pointers.
+ if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
+ return;
+ }
+
+ // Okay to skip binder because what we are inspecting doesn't involve bound regions.
+ let self_ty = obligation.self_ty().skip_binder();
+ match *self_ty.kind() {
+ ty::Infer(ty::TyVar(_)) => {
+ debug!("assemble_fn_pointer_candidates: ambiguous self-type");
+ candidates.ambiguous = true; // Could wind up being a fn() type.
+ }
+ // Provide an impl, but only for suitable `fn` pointers.
+ ty::FnPtr(_) => {
+ if let ty::FnSig {
+ unsafety: hir::Unsafety::Normal,
+ abi: Abi::Rust,
+ c_variadic: false,
+ ..
+ } = self_ty.fn_sig(self.tcx()).skip_binder()
+ {
+ candidates.vec.push(FnPointerCandidate { is_const: false });
+ }
+ }
+ // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
+ ty::FnDef(def_id, _) => {
+ if let ty::FnSig {
+ unsafety: hir::Unsafety::Normal,
+ abi: Abi::Rust,
+ c_variadic: false,
+ ..
+ } = self_ty.fn_sig(self.tcx()).skip_binder()
+ {
+ if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
+ candidates
+ .vec
+ .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) });
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+
+ /// Searches for impls that might apply to `obligation`.
+ fn assemble_candidates_from_impls(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ debug!(?obligation, "assemble_candidates_from_impls");
+
+ // Essentially any user-written impl will match with an error type,
+ // so creating `ImplCandidates` isn't useful. However, we might
+ // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized)
+ // This helps us avoid overflow: see issue #72839
+ // Since compilation is already guaranteed to fail, this is just
+ // to try to show the 'nicest' possible errors to the user.
+ // We don't check for errors in the `ParamEnv` - in practice,
+ // it seems to cause us to be overly aggressive in deciding
+ // to give up searching for candidates, leading to spurious errors.
+ if obligation.predicate.references_error() {
+ return;
+ }
+
+ self.tcx().for_each_relevant_impl(
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().trait_ref.self_ty(),
+ |impl_def_id| {
+ // Before we create the substitutions and everything, first
+ // consider a "quick reject". This avoids creating more types
+ // and so forth that we need to.
+ let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+ if self.fast_reject_trait_refs(obligation, &impl_trait_ref.0) {
+ return;
+ }
+
+ self.infcx.probe(|_| {
+ if let Ok(_substs) = self.match_impl(impl_def_id, impl_trait_ref, obligation) {
+ candidates.vec.push(ImplCandidate(impl_def_id));
+ }
+ });
+ },
+ );
+ }
+
+ fn assemble_candidates_from_auto_impls(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ // Okay to skip binder here because the tests we do below do not involve bound regions.
+ let self_ty = obligation.self_ty().skip_binder();
+ debug!(?self_ty, "assemble_candidates_from_auto_impls");
+
+ let def_id = obligation.predicate.def_id();
+
+ if self.tcx().trait_is_auto(def_id) {
+ match self_ty.kind() {
+ ty::Dynamic(..) => {
+ // For object types, we don't know what the closed
+ // over types are. This means we conservatively
+ // say nothing; a candidate may be added by
+ // `assemble_candidates_from_object_ty`.
+ }
+ ty::Foreign(..) => {
+ // Since the contents of foreign types is unknown,
+ // we don't add any `..` impl. Default traits could
+ // still be provided by a manual implementation for
+ // this trait and type.
+ }
+ ty::Param(..) | ty::Projection(..) => {
+ // In these cases, we don't know what the actual
+ // type is. Therefore, we cannot break it down
+ // into its constituent types. So we don't
+ // consider the `..` impl but instead just add no
+ // candidates: this means that typeck will only
+ // succeed if there is another reason to believe
+ // that this obligation holds. That could be a
+ // where-clause or, in the case of an object type,
+ // it could be that the object type lists the
+ // trait (e.g., `Foo+Send : Send`). See
+ // `ui/typeck/typeck-default-trait-impl-send-param.rs`
+ // for an example of a test case that exercises
+ // this path.
+ }
+ ty::Infer(ty::TyVar(_)) => {
+ // The auto impl might apply; we don't know.
+ candidates.ambiguous = true;
+ }
+ ty::Generator(_, _, movability)
+ if self.tcx().lang_items().unpin_trait() == Some(def_id) =>
+ {
+ match movability {
+ hir::Movability::Static => {
+ // Immovable generators are never `Unpin`, so
+ // suppress the normal auto-impl candidate for it.
+ }
+ hir::Movability::Movable => {
+ // Movable generators are always `Unpin`, so add an
+ // unconditional builtin candidate.
+ candidates.vec.push(BuiltinCandidate { has_nested: false });
+ }
+ }
+ }
+
+ _ => candidates.vec.push(AutoImplCandidate(def_id)),
+ }
+ }
+ }
+
+ /// Searches for impls that might apply to `obligation`.
+ fn assemble_candidates_from_object_ty(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ debug!(
+ self_ty = ?obligation.self_ty().skip_binder(),
+ "assemble_candidates_from_object_ty",
+ );
+
+ self.infcx.probe(|_snapshot| {
+ // 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() {
+ ty::Dynamic(ref data, ..) => {
+ if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
+ debug!(
+ "assemble_candidates_from_object_ty: matched builtin bound, \
+ pushing candidate"
+ );
+ candidates.vec.push(BuiltinObjectCandidate);
+ return;
+ }
+
+ if let Some(principal) = data.principal() {
+ if !self.infcx.tcx.features().object_safe_for_dispatch {
+ principal.with_self_ty(self.tcx(), self_ty)
+ } else if self.tcx().is_object_safe(principal.def_id()) {
+ principal.with_self_ty(self.tcx(), self_ty)
+ } else {
+ return;
+ }
+ } else {
+ // Only auto trait bounds exist.
+ return;
+ }
+ }
+ ty::Infer(ty::TyVar(_)) => {
+ debug!("assemble_candidates_from_object_ty: ambiguous");
+ candidates.ambiguous = true; // could wind up being an object type
+ return;
+ }
+ _ => 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().replace_bound_vars_with_placeholders(poly_trait_predicate);
+
+ // 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)
+ .enumerate()
+ .filter(|&(_, upcast_trait_ref)| {
+ self.infcx.probe(|_| {
+ self.match_normalize_trait_ref(
+ obligation,
+ upcast_trait_ref,
+ placeholder_trait_predicate.trait_ref,
+ )
+ .is_ok()
+ })
+ })
+ .map(|(idx, _)| ObjectCandidate(idx));
+
+ candidates.vec.extend(candidate_supertraits);
+ })
+ }
+
+ /// Temporary migration for #89190
+ fn need_migrate_deref_output_trait_object(
+ &mut self,
+ ty: Ty<'tcx>,
+ cause: &traits::ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Option<(Ty<'tcx>, DefId)> {
+ let tcx = self.tcx();
+ if tcx.features().trait_upcasting {
+ return None;
+ }
+
+ // <ty as Deref>
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.lang_items().deref_trait()?,
+ substs: tcx.mk_substs_trait(ty, &[]),
+ };
+
+ let obligation = traits::Obligation::new(
+ cause.clone(),
+ param_env,
+ ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+ );
+ if !self.infcx.predicate_may_hold(&obligation) {
+ return None;
+ }
+
+ let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
+ let normalized_ty = fulfillcx.normalize_projection_type(
+ &self.infcx,
+ param_env,
+ ty::ProjectionTy {
+ item_def_id: tcx.lang_items().deref_target()?,
+ substs: trait_ref.substs,
+ },
+ cause.clone(),
+ );
+
+ let ty::Dynamic(data, ..) = normalized_ty.kind() else {
+ return None;
+ };
+
+ let def_id = data.principal_def_id()?;
+
+ return Some((normalized_ty, def_id));
+ }
+
+ /// Searches for unsizing that might apply to `obligation`.
+ fn assemble_candidates_for_unsizing(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ // We currently never consider higher-ranked obligations e.g.
+ // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not
+ // because they are a priori invalid, and we could potentially add support
+ // for them later, it's just that there isn't really a strong need for it.
+ // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>`
+ // impl, and those are generally applied to concrete types.
+ //
+ // That said, one might try to write a fn with a where clause like
+ // for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>>
+ // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`.
+ // Still, you'd be more likely to write that where clause as
+ // T: Trait
+ // so it seems ok if we (conservatively) fail to accept that `Unsize`
+ // obligation above. Should be possible to extend this in the future.
+ let Some(source) = obligation.self_ty().no_bound_vars() else {
+ // Don't add any candidates if there are bound regions.
+ return;
+ };
+ let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+
+ debug!(?source, ?target, "assemble_candidates_for_unsizing");
+
+ match (source.kind(), target.kind()) {
+ // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
+ (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+ // Upcast coercions permit several things:
+ //
+ // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
+ // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
+ // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
+ //
+ // Note that neither of the first two of these changes requires any
+ // change at runtime. The third needs to change pointer metadata at runtime.
+ //
+ // We always perform upcasting coercions when we can because of reason
+ // #2 (region bounds).
+ let auto_traits_compatible = data_b
+ .auto_traits()
+ // All of a's auto traits need to be in b's auto traits.
+ .all(|b| data_a.auto_traits().any(|a| a == b));
+ if auto_traits_compatible {
+ let principal_def_id_a = data_a.principal_def_id();
+ let principal_def_id_b = data_b.principal_def_id();
+ if principal_def_id_a == principal_def_id_b {
+ // no cyclic
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
+ // not casual unsizing, now check whether this is trait upcasting coercion.
+ let principal_a = data_a.principal().unwrap();
+ let target_trait_did = principal_def_id_b.unwrap();
+ let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
+ if let Some((deref_output_ty, deref_output_trait_did)) = self
+ .need_migrate_deref_output_trait_object(
+ source,
+ &obligation.cause,
+ obligation.param_env,
+ )
+ {
+ if deref_output_trait_did == target_trait_did {
+ self.tcx().struct_span_lint_hir(
+ DEREF_INTO_DYN_SUPERTRAIT,
+ obligation.cause.body_id,
+ obligation.cause.span,
+ |lint| {
+ lint.build(&format!(
+ "`{}` implements `Deref` with supertrait `{}` as output",
+ source,
+ deref_output_ty
+ )).emit();
+ },
+ );
+ return;
+ }
+ }
+
+ for (idx, upcast_trait_ref) in
+ util::supertraits(self.tcx(), source_trait_ref).enumerate()
+ {
+ if upcast_trait_ref.def_id() == target_trait_did {
+ candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
+ }
+ }
+ }
+ }
+ }
+
+ // `T` -> `Trait`
+ (_, &ty::Dynamic(..)) => {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
+
+ // Ambiguous handling is below `T` -> `Trait`, because inference
+ // variables can still implement `Unsize<Trait>` and nested
+ // obligations will have the final say (likely deferred).
+ (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
+ debug!("assemble_candidates_for_unsizing: ambiguous");
+ candidates.ambiguous = true;
+ }
+
+ // `[T; n]` -> `[T]`
+ (&ty::Array(..), &ty::Slice(_)) => {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
+
+ // `Struct<T>` -> `Struct<U>`
+ (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
+ if def_id_a == def_id_b {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
+ }
+
+ // `(.., T)` -> `(.., U)`
+ (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
+ if tys_a.len() == tys_b.len() {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
+ }
+
+ _ => {}
+ };
+ }
+
+ #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ fn assemble_candidates_for_transmutability(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ if obligation.has_param_types_or_consts() {
+ return;
+ }
+
+ if obligation.has_infer_types_or_consts() {
+ candidates.ambiguous = true;
+ return;
+ }
+
+ candidates.vec.push(TransmutabilityCandidate);
+ }
+
+ #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ fn assemble_candidates_for_trait_alias(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ // Okay to skip binder here because the tests we do below do not involve bound regions.
+ let self_ty = obligation.self_ty().skip_binder();
+ debug!(?self_ty);
+
+ let def_id = obligation.predicate.def_id();
+
+ if self.tcx().is_trait_alias(def_id) {
+ candidates.vec.push(TraitAliasCandidate(def_id));
+ }
+ }
+
+ /// Assembles the trait which are built-in to the language itself:
+ /// `Copy`, `Clone` and `Sized`.
+ #[tracing::instrument(level = "debug", skip(self, candidates))]
+ fn assemble_builtin_bound_candidates(
+ &mut self,
+ conditions: BuiltinImplConditions<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ match conditions {
+ BuiltinImplConditions::Where(nested) => {
+ candidates
+ .vec
+ .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() });
+ }
+ BuiltinImplConditions::None => {}
+ BuiltinImplConditions::Ambiguous => {
+ candidates.ambiguous = true;
+ }
+ }
+ }
+
+ fn assemble_const_destruct_candidates(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ // If the predicate is `~const Destruct` in a non-const environment, we don't actually need
+ // to check anything. We'll short-circuit checking any obligations in confirmation, too.
+ if !obligation.is_const() {
+ candidates.vec.push(ConstDestructCandidate(None));
+ return;
+ }
+
+ let self_ty = self.infcx().shallow_resolve(obligation.self_ty());
+ match self_ty.skip_binder().kind() {
+ ty::Opaque(..)
+ | ty::Dynamic(..)
+ | ty::Error(_)
+ | ty::Bound(..)
+ | ty::Param(_)
+ | ty::Placeholder(_)
+ | ty::Projection(_) => {
+ // We don't know if these are `~const Destruct`, at least
+ // not structurally... so don't push a candidate.
+ }
+
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Str
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Foreign(_)
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::Closure(..)
+ | ty::Generator(..)
+ | ty::Tuple(_)
+ | ty::GeneratorWitness(_) => {
+ // These are built-in, and cannot have a custom `impl const Destruct`.
+ candidates.vec.push(ConstDestructCandidate(None));
+ }
+
+ ty::Adt(..) => {
+ // Find a custom `impl Drop` impl, if it exists
+ let relevant_impl = self.tcx().find_map_relevant_impl(
+ self.tcx().require_lang_item(LangItem::Drop, None),
+ obligation.predicate.skip_binder().trait_ref.self_ty(),
+ Some,
+ );
+
+ if let Some(impl_def_id) = relevant_impl {
+ // Check that `impl Drop` is actually const, if there is a custom impl
+ if self.tcx().constness(impl_def_id) == hir::Constness::Const {
+ candidates.vec.push(ConstDestructCandidate(Some(impl_def_id)));
+ }
+ } else {
+ // Otherwise check the ADT like a built-in type (structurally)
+ candidates.vec.push(ConstDestructCandidate(None));
+ }
+ }
+
+ ty::Infer(_) => {
+ candidates.ambiguous = true;
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
new file mode 100644
index 000000000..2a1099fc8
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -0,0 +1,1266 @@
+//! Confirmation.
+//!
+//! Confirmation unifies the output type parameters of the trait
+//! with the values found in the obligation, possibly yielding a
+//! type error. See the [rustc dev guide] for more details.
+//!
+//! [rustc dev guide]:
+//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_hir::lang_items::LangItem;
+use rustc_index::bit_set::GrowableBitSet;
+use rustc_infer::infer::InferOk;
+use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt};
+use rustc_middle::ty::{ToPolyTraitRef, ToPredicate};
+use rustc_span::def_id::DefId;
+
+use crate::traits::project::{normalize_with_depth, normalize_with_depth_to};
+use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def};
+use crate::traits::{
+ BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
+ ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
+ ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
+ ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
+ ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
+ Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
+ SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment,
+};
+
+use super::BuiltinImplConditions;
+use super::SelectionCandidate::{self, *};
+use super::SelectionContext;
+
+use std::iter;
+use std::ops::ControlFlow;
+
+impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+ #[instrument(level = "debug", skip(self))]
+ pub(super) fn confirm_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidate: SelectionCandidate<'tcx>,
+ ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
+ let mut impl_src = match candidate {
+ BuiltinCandidate { has_nested } => {
+ let data = self.confirm_builtin_candidate(obligation, has_nested);
+ ImplSource::Builtin(data)
+ }
+
+ TransmutabilityCandidate => {
+ let data = self.confirm_transmutability_candidate(obligation)?;
+ ImplSource::Builtin(data)
+ }
+
+ ParamCandidate(param) => {
+ let obligations =
+ self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
+ ImplSource::Param(obligations, param.skip_binder().constness)
+ }
+
+ ImplCandidate(impl_def_id) => {
+ ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))
+ }
+
+ AutoImplCandidate(trait_def_id) => {
+ let data = self.confirm_auto_impl_candidate(obligation, trait_def_id);
+ ImplSource::AutoImpl(data)
+ }
+
+ ProjectionCandidate(idx) => {
+ let obligations = self.confirm_projection_candidate(obligation, idx)?;
+ // FIXME(jschievink): constness
+ ImplSource::Param(obligations, ty::BoundConstness::NotConst)
+ }
+
+ ObjectCandidate(idx) => {
+ let data = self.confirm_object_candidate(obligation, idx)?;
+ ImplSource::Object(data)
+ }
+
+ ClosureCandidate => {
+ let vtable_closure = self.confirm_closure_candidate(obligation)?;
+ ImplSource::Closure(vtable_closure)
+ }
+
+ GeneratorCandidate => {
+ let vtable_generator = self.confirm_generator_candidate(obligation)?;
+ ImplSource::Generator(vtable_generator)
+ }
+
+ FnPointerCandidate { .. } => {
+ let data = self.confirm_fn_pointer_candidate(obligation)?;
+ ImplSource::FnPointer(data)
+ }
+
+ DiscriminantKindCandidate => {
+ ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+ }
+
+ PointeeCandidate => ImplSource::Pointee(ImplSourcePointeeData),
+
+ TraitAliasCandidate(alias_def_id) => {
+ let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
+ ImplSource::TraitAlias(data)
+ }
+
+ BuiltinObjectCandidate => {
+ // This indicates something like `Trait + Send: Send`. In this case, we know that
+ // this holds because that's what the object type is telling us, and there's really
+ // no additional obligations to prove and no types in particular to unify, etc.
+ ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst)
+ }
+
+ BuiltinUnsizeCandidate => {
+ let data = self.confirm_builtin_unsize_candidate(obligation)?;
+ ImplSource::Builtin(data)
+ }
+
+ TraitUpcastingUnsizeCandidate(idx) => {
+ let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
+ ImplSource::TraitUpcasting(data)
+ }
+
+ ConstDestructCandidate(def_id) => {
+ let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
+ ImplSource::ConstDestruct(data)
+ }
+ };
+
+ if !obligation.predicate.is_const_if_const() {
+ // normalize nested predicates according to parent predicate's constness.
+ impl_src = impl_src.map(|mut o| {
+ o.predicate = o.predicate.without_const(self.tcx());
+ o
+ });
+ }
+
+ Ok(impl_src)
+ }
+
+ fn confirm_projection_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ idx: usize,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ let tcx = self.tcx();
+
+ let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
+ let placeholder_trait_predicate =
+ self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+ let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+ let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
+ let (def_id, substs) = match *placeholder_self_ty.kind() {
+ ty::Projection(proj) => (proj.item_def_id, proj.substs),
+ ty::Opaque(def_id, substs) => (def_id, substs),
+ _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
+ };
+
+ let candidate_predicate =
+ tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
+ let candidate = candidate_predicate
+ .to_opt_poly_trait_pred()
+ .expect("projection candidate is not a trait predicate")
+ .map_bound(|t| t.trait_ref);
+ let mut obligations = Vec::new();
+ let candidate = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ candidate,
+ &mut obligations,
+ );
+
+ obligations.extend(self.infcx.commit_if_ok(|_| {
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(placeholder_trait_predicate, candidate)
+ .map(|InferOk { obligations, .. }| obligations)
+ .map_err(|_| Unimplemented)
+ })?);
+
+ if let ty::Projection(..) = placeholder_self_ty.kind() {
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
+ debug!(?predicates, "projection predicates");
+ for predicate in predicates {
+ let normalized = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ predicate,
+ &mut obligations,
+ );
+ obligations.push(Obligation::with_depth(
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ normalized,
+ ));
+ }
+ }
+
+ Ok(obligations)
+ }
+
+ fn confirm_param_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ param: ty::PolyTraitRef<'tcx>,
+ ) -> Vec<PredicateObligation<'tcx>> {
+ debug!(?obligation, ?param, "confirm_param_candidate");
+
+ // During evaluation, we already checked that this
+ // where-clause trait-ref could be unified with the obligation
+ // trait-ref. Repeat that unification now without any
+ // transactional boundary; it should not fail.
+ match self.match_where_clause_trait_ref(obligation, param) {
+ Ok(obligations) => obligations,
+ Err(()) => {
+ bug!(
+ "Where clause `{:?}` was applicable to `{:?}` but now is not",
+ param,
+ obligation
+ );
+ }
+ }
+ }
+
+ fn confirm_builtin_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ has_nested: bool,
+ ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> {
+ debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
+
+ let lang_items = self.tcx().lang_items();
+ let obligations = if has_nested {
+ let trait_def = obligation.predicate.def_id();
+ let conditions = if Some(trait_def) == lang_items.sized_trait() {
+ self.sized_conditions(obligation)
+ } else if Some(trait_def) == lang_items.copy_trait() {
+ self.copy_clone_conditions(obligation)
+ } else if Some(trait_def) == lang_items.clone_trait() {
+ self.copy_clone_conditions(obligation)
+ } else {
+ bug!("unexpected builtin trait {:?}", trait_def)
+ };
+ let BuiltinImplConditions::Where(nested) = conditions else {
+ bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation);
+ };
+
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+ ensure_sufficient_stack(|| {
+ self.collect_predicates_for_types(
+ obligation.param_env,
+ cause,
+ obligation.recursion_depth + 1,
+ trait_def,
+ nested,
+ )
+ })
+ } else {
+ vec![]
+ };
+
+ debug!(?obligations);
+
+ ImplSourceBuiltinData { nested: obligations }
+ }
+
+ fn confirm_transmutability_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ debug!(?obligation, "confirm_transmutability_candidate");
+
+ let predicate = obligation.predicate;
+
+ let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
+ let bool_at = |i| {
+ predicate
+ .skip_binder()
+ .trait_ref
+ .substs
+ .const_at(i)
+ .try_eval_bool(self.tcx(), obligation.param_env)
+ .unwrap_or(true)
+ };
+
+ let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
+ src: p.trait_ref.substs.type_at(1),
+ dst: p.trait_ref.substs.type_at(0),
+ });
+
+ let scope = type_at(2).skip_binder();
+
+ let assume = rustc_transmute::Assume {
+ alignment: bool_at(3),
+ lifetimes: bool_at(4),
+ validity: bool_at(5),
+ visibility: bool_at(6),
+ };
+
+ let cause = obligation.cause.clone();
+
+ let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
+
+ let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
+
+ use rustc_transmute::Answer;
+
+ match maybe_transmutable {
+ Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+ _ => Err(Unimplemented),
+ }
+ }
+
+ /// This handles the case where an `auto trait Foo` impl is being used.
+ /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
+ ///
+ /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
+ /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds.
+ fn confirm_auto_impl_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_def_id: DefId,
+ ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
+ debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate");
+
+ let self_ty = self.infcx.shallow_resolve(obligation.predicate.self_ty());
+ let types = self.constituent_types_for_ty(self_ty);
+ self.vtable_auto_impl(obligation, trait_def_id, types)
+ }
+
+ /// See `confirm_auto_impl_candidate`.
+ fn vtable_auto_impl(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_def_id: DefId,
+ nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
+ ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
+ debug!(?nested, "vtable_auto_impl");
+ ensure_sufficient_stack(|| {
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+ let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+ let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
+ let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
+ &cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ trait_def_id,
+ &trait_ref.substs,
+ obligation.predicate,
+ );
+
+ let mut obligations = self.collect_predicates_for_types(
+ obligation.param_env,
+ cause,
+ obligation.recursion_depth + 1,
+ trait_def_id,
+ nested,
+ );
+
+ // Adds the predicates from the trait. Note that this contains a `Self: Trait`
+ // predicate as usual. It won't have any effect since auto traits are coinductive.
+ obligations.extend(trait_obligations);
+
+ debug!(?obligations, "vtable_auto_impl");
+
+ ImplSourceAutoImplData { trait_def_id, nested: obligations }
+ })
+ }
+
+ fn confirm_impl_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ impl_def_id: DefId,
+ ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
+ debug!(?obligation, ?impl_def_id, "confirm_impl_candidate");
+
+ // First, create the substitutions by matching the impl again,
+ // this time not in a probe.
+ let substs = self.rematch_impl(impl_def_id, obligation);
+ debug!(?substs, "impl substs");
+ ensure_sufficient_stack(|| {
+ self.vtable_impl(
+ impl_def_id,
+ substs,
+ &obligation.cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ obligation.predicate,
+ )
+ })
+ }
+
+ fn vtable_impl(
+ &mut self,
+ impl_def_id: DefId,
+ substs: Normalized<'tcx, SubstsRef<'tcx>>,
+ cause: &ObligationCause<'tcx>,
+ recursion_depth: usize,
+ param_env: ty::ParamEnv<'tcx>,
+ parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
+ debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl");
+
+ let mut impl_obligations = self.impl_or_trait_obligations(
+ cause,
+ recursion_depth,
+ param_env,
+ impl_def_id,
+ &substs.value,
+ parent_trait_pred,
+ );
+
+ debug!(?impl_obligations, "vtable_impl");
+
+ // Because of RFC447, the impl-trait-ref and obligations
+ // are sufficient to determine the impl substs, without
+ // relying on projections in the impl-trait-ref.
+ //
+ // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V`
+ impl_obligations.extend(substs.obligations);
+
+ ImplSourceUserDefinedData { impl_def_id, substs: substs.value, nested: impl_obligations }
+ }
+
+ fn confirm_object_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ index: usize,
+ ) -> Result<ImplSourceObjectData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ let tcx = self.tcx();
+ debug!(?obligation, ?index, "confirm_object_candidate");
+
+ let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty());
+ let obligation_trait_ref = ty::Binder::dummy(trait_predicate.trait_ref);
+ let ty::Dynamic(data, ..) = *self_ty.kind() else {
+ span_bug!(obligation.cause.span, "object candidate with non-object");
+ };
+
+ let object_trait_ref = data.principal().unwrap_or_else(|| {
+ span_bug!(obligation.cause.span, "object candidate with no principal")
+ });
+ let object_trait_ref = self.infcx.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ HigherRankedType,
+ object_trait_ref,
+ );
+ let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty);
+
+ let mut nested = vec![];
+
+ let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref));
+ let unnormalized_upcast_trait_ref =
+ supertraits.nth(index).expect("supertraits iterator no longer has as many elements");
+
+ let upcast_trait_ref = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ unnormalized_upcast_trait_ref,
+ &mut nested,
+ );
+
+ nested.extend(self.infcx.commit_if_ok(|_| {
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(obligation_trait_ref, upcast_trait_ref)
+ .map(|InferOk { obligations, .. }| obligations)
+ .map_err(|_| Unimplemented)
+ })?);
+
+ // Check supertraits hold. This is so that their associated type bounds
+ // will be checked in the code below.
+ for super_trait in tcx
+ .super_predicates_of(trait_predicate.def_id())
+ .instantiate(tcx, trait_predicate.trait_ref.substs)
+ .predicates
+ .into_iter()
+ {
+ let normalized_super_trait = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ super_trait,
+ &mut nested,
+ );
+ nested.push(Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ normalized_super_trait,
+ ));
+ }
+
+ let assoc_types: Vec<_> = tcx
+ .associated_items(trait_predicate.def_id())
+ .in_definition_order()
+ .filter_map(
+ |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
+ )
+ .collect();
+
+ for assoc_type in assoc_types {
+ let defs: &ty::Generics = tcx.generics_of(assoc_type);
+
+ if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
+ tcx.sess.delay_span_bug(
+ obligation.cause.span,
+ "GATs in trait object shouldn't have been considered",
+ );
+ return Err(SelectionError::Unimplemented);
+ }
+
+ // This maybe belongs in wf, but that can't (doesn't) handle
+ // higher-ranked things.
+ // Prevent, e.g., `dyn Iterator<Item = str>`.
+ for bound in self.tcx().bound_item_bounds(assoc_type).transpose_iter() {
+ let subst_bound =
+ if defs.count() == 0 {
+ bound.subst(tcx, trait_predicate.trait_ref.substs)
+ } else {
+ let mut substs = smallvec::SmallVec::with_capacity(defs.count());
+ substs.extend(trait_predicate.trait_ref.substs.iter());
+ let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
+ smallvec::SmallVec::with_capacity(
+ bound.0.kind().bound_vars().len() + defs.count(),
+ );
+ bound_vars.extend(bound.0.kind().bound_vars().into_iter());
+ InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param
+ .kind
+ {
+ GenericParamDefKind::Type { .. } => {
+ let kind = ty::BoundTyKind::Param(param.name);
+ let bound_var = ty::BoundVariableKind::Ty(kind);
+ bound_vars.push(bound_var);
+ tcx.mk_ty(ty::Bound(
+ ty::INNERMOST,
+ ty::BoundTy {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind,
+ },
+ ))
+ .into()
+ }
+ GenericParamDefKind::Lifetime => {
+ let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
+ let bound_var = ty::BoundVariableKind::Region(kind);
+ bound_vars.push(bound_var);
+ tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion {
+ var: ty::BoundVar::from_usize(bound_vars.len() - 1),
+ kind,
+ },
+ ))
+ .into()
+ }
+ GenericParamDefKind::Const { .. } => {
+ let bound_var = ty::BoundVariableKind::Const;
+ bound_vars.push(bound_var);
+ tcx.mk_const(ty::ConstS {
+ ty: tcx.type_of(param.def_id),
+ kind: ty::ConstKind::Bound(
+ ty::INNERMOST,
+ ty::BoundVar::from_usize(bound_vars.len() - 1),
+ ),
+ })
+ .into()
+ }
+ });
+ let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
+ let assoc_ty_substs = tcx.intern_substs(&substs);
+
+ let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
+ let bound =
+ bound.map_bound(|b| b.kind().skip_binder()).subst(tcx, assoc_ty_substs);
+ tcx.mk_predicate(ty::Binder::bind_with_vars(bound, bound_vars))
+ };
+ let normalized_bound = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ subst_bound,
+ &mut nested,
+ );
+ nested.push(Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ normalized_bound,
+ ));
+ }
+ }
+
+ debug!(?nested, "object nested obligations");
+
+ let vtable_base = super::super::vtable_trait_first_method_offset(
+ tcx,
+ (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
+ );
+
+ Ok(ImplSourceObjectData { upcast_trait_ref, vtable_base, nested })
+ }
+
+ fn confirm_fn_pointer_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
+ {
+ debug!(?obligation, "confirm_fn_pointer_candidate");
+
+ // Okay to skip binder; it is reintroduced below.
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
+ let sig = self_ty.fn_sig(self.tcx());
+ let trait_ref = closure_trait_ref_and_return_type(
+ self.tcx(),
+ obligation.predicate.def_id(),
+ self_ty,
+ sig,
+ util::TupleArgumentsFlag::Yes,
+ )
+ .map_bound(|(trait_ref, _)| trait_ref);
+
+ let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested })
+ }
+
+ fn confirm_trait_alias_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ alias_def_id: DefId,
+ ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
+ debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
+
+ let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
+ let trait_ref = predicate.trait_ref;
+ let trait_def_id = trait_ref.def_id;
+ let substs = trait_ref.substs;
+
+ let trait_obligations = self.impl_or_trait_obligations(
+ &obligation.cause,
+ obligation.recursion_depth,
+ obligation.param_env,
+ trait_def_id,
+ &substs,
+ obligation.predicate,
+ );
+
+ debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
+
+ ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
+ }
+
+ fn confirm_generator_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
+ {
+ // Okay to skip binder because the substs on generator 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, substs, _) = *self_ty.kind() else {
+ bug!("closure candidate for non-closure {:?}", obligation);
+ };
+
+ debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate");
+
+ let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs);
+
+ let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+ debug!(?trait_ref, ?nested, "generator candidate obligations");
+
+ Ok(ImplSourceGeneratorData { generator_def_id, substs, nested })
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn confirm_closure_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ let kind = self
+ .tcx()
+ .fn_trait_kind_from_lang_item(obligation.predicate.def_id())
+ .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation));
+
+ // Okay to skip binder because the substs on closure 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::Closure(closure_def_id, substs) = *self_ty.kind() else {
+ bug!("closure candidate for non-closure {:?}", obligation);
+ };
+
+ let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
+ let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
+
+ debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
+
+ // FIXME: Chalk
+
+ if !self.tcx().sess.opts.unstable_opts.chalk {
+ nested.push(Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind))
+ .to_predicate(self.tcx()),
+ ));
+ }
+
+ Ok(ImplSourceClosureData { closure_def_id, substs, nested })
+ }
+
+ /// In the case of closure types and fn pointers,
+ /// we currently treat the input type parameters on the trait as
+ /// outputs. This means that when we have a match we have only
+ /// considered the self type, so we have to go back and make sure
+ /// to relate the argument types too. This is kind of wrong, but
+ /// since we control the full set of impls, also not that wrong,
+ /// and it DOES yield better error messages (since we don't report
+ /// errors as if there is no applicable impl, but rather report
+ /// errors are about mismatched argument types.
+ ///
+ /// Here is an example. Imagine we have a closure expression
+ /// and we desugared it so that the type of the expression is
+ /// `Closure`, and `Closure` expects `i32` as argument. Then it
+ /// is "as if" the compiler generated this impl:
+ /// ```ignore (illustrative)
+ /// impl Fn(i32) for Closure { ... }
+ /// ```
+ /// Now imagine our obligation is `Closure: Fn(usize)`. So far
+ /// we have matched the self type `Closure`. At this point we'll
+ /// compare the `i32` to `usize` and generate an error.
+ ///
+ /// Note that this checking occurs *after* the impl has selected,
+ /// because these output type parameters should not affect the
+ /// selection of the impl. Therefore, if there is a mismatch, we
+ /// report an error to the user.
+ #[instrument(skip(self), level = "trace")]
+ fn confirm_poly_trait_refs(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ expected_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
+ // Normalize the obligation and expected trait refs together, because why not
+ let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ (obligation_trait_ref, expected_trait_ref),
+ )
+ });
+
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(obligation_trait_ref, expected_trait_ref)
+ .map(|InferOk { mut obligations, .. }| {
+ obligations.extend(nested);
+ obligations
+ })
+ .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
+ }
+
+ fn confirm_trait_upcasting_unsize_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ idx: usize,
+ ) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
+ {
+ let tcx = self.tcx();
+
+ // `assemble_candidates_for_unsizing` should ensure there are no late-bound
+ // regions here. See the comment there for more details.
+ let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+ let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+ let target = self.infcx.shallow_resolve(target);
+
+ debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
+
+ let mut nested = vec![];
+ let source_trait_ref;
+ let upcast_trait_ref;
+ match (source.kind(), target.kind()) {
+ // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
+ (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
+ // See `assemble_candidates_for_unsizing` for more info.
+ // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
+ let principal_a = data_a.principal().unwrap();
+ source_trait_ref = principal_a.with_self_ty(tcx, source);
+ upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
+ assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id()));
+ let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
+ tcx, trait_ref,
+ ))
+ });
+ let iter = Some(existential_predicate)
+ .into_iter()
+ .chain(
+ data_a
+ .projection_bounds()
+ .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+ )
+ .chain(
+ data_b
+ .auto_traits()
+ .map(ty::ExistentialPredicate::AutoTrait)
+ .map(ty::Binder::dummy),
+ );
+ let existential_predicates = tcx.mk_poly_existential_predicates(iter);
+ let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+
+ // Require that the traits involved in this upcast are **equal**;
+ // only the **lifetime bound** is changed.
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(target, source_trait)
+ .map_err(|_| Unimplemented)?;
+ nested.extend(obligations);
+
+ // Register one obligation for 'a: 'b.
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObjectCastObligation(source, target),
+ );
+ let outlives = ty::OutlivesPredicate(r_a, r_b);
+ nested.push(Obligation::with_depth(
+ cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ obligation.predicate.rebind(outlives).to_predicate(tcx),
+ ));
+ }
+ _ => bug!(),
+ };
+
+ let vtable_segment_callback = {
+ let mut vptr_offset = 0;
+ move |segment| {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
+ if trait_ref == upcast_trait_ref {
+ if emit_vptr {
+ return ControlFlow::Break(Some(vptr_offset));
+ } else {
+ return ControlFlow::Break(None);
+ }
+ }
+
+ if emit_vptr {
+ vptr_offset += 1;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+ };
+
+ let vtable_vptr_slot =
+ super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback)
+ .unwrap();
+
+ Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
+ }
+
+ fn confirm_builtin_unsize_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ let tcx = self.tcx();
+
+ // `assemble_candidates_for_unsizing` should ensure there are no late-bound
+ // regions here. See the comment there for more details.
+ let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+ let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+ let target = self.infcx.shallow_resolve(target);
+
+ debug!(?source, ?target, "confirm_builtin_unsize_candidate");
+
+ let mut nested = vec![];
+ match (source.kind(), target.kind()) {
+ // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
+ (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
+ // See `assemble_candidates_for_unsizing` for more info.
+ // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`.
+ let iter = data_a
+ .principal()
+ .map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
+ .into_iter()
+ .chain(
+ data_a
+ .projection_bounds()
+ .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+ )
+ .chain(
+ data_b
+ .auto_traits()
+ .map(ty::ExistentialPredicate::AutoTrait)
+ .map(ty::Binder::dummy),
+ );
+ let existential_predicates = tcx.mk_poly_existential_predicates(iter);
+ let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+
+ // Require that the traits involved in this upcast are **equal**;
+ // only the **lifetime bound** is changed.
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(target, source_trait)
+ .map_err(|_| Unimplemented)?;
+ nested.extend(obligations);
+
+ // Register one obligation for 'a: 'b.
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObjectCastObligation(source, target),
+ );
+ let outlives = ty::OutlivesPredicate(r_a, r_b);
+ nested.push(Obligation::with_depth(
+ cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ obligation.predicate.rebind(outlives).to_predicate(tcx),
+ ));
+ }
+
+ // `T` -> `Trait`
+ (_, &ty::Dynamic(ref data, r)) => {
+ let mut object_dids = data.auto_traits().chain(data.principal_def_id());
+ if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
+ return Err(TraitNotObjectSafe(did));
+ }
+
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObjectCastObligation(source, target),
+ );
+
+ let predicate_to_obligation = |predicate| {
+ Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ )
+ };
+
+ // Create obligations:
+ // - Casting `T` to `Trait`
+ // - For all the various builtin bounds attached to the object cast. (In other
+ // words, if the object type is `Foo + Send`, this would create an obligation for
+ // the `Send` check.)
+ // - Projection predicates
+ nested.extend(
+ data.iter().map(|predicate| {
+ predicate_to_obligation(predicate.with_self_ty(tcx, source))
+ }),
+ );
+
+ // We can only make objects from sized types.
+ let tr = ty::Binder::dummy(ty::TraitRef::new(
+ tcx.require_lang_item(LangItem::Sized, None),
+ tcx.mk_substs_trait(source, &[]),
+ ));
+ nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
+
+ // If the type is `Foo + 'a`, ensure that the type
+ // being cast to `Foo + 'a` outlives `'a`:
+ let outlives = ty::OutlivesPredicate(source, r);
+ nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate(tcx)));
+ }
+
+ // `[T; n]` -> `[T]`
+ (&ty::Array(a, _), &ty::Slice(b)) => {
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(b, a)
+ .map_err(|_| Unimplemented)?;
+ nested.extend(obligations);
+ }
+
+ // `Struct<T>` -> `Struct<U>`
+ (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => {
+ let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() {
+ GenericArgKind::Type(ty) => match ty.kind() {
+ ty::Param(p) => Some(p.index),
+ _ => None,
+ },
+
+ // Lifetimes aren't allowed to change during unsizing.
+ GenericArgKind::Lifetime(_) => None,
+
+ GenericArgKind::Const(ct) => match ct.kind() {
+ ty::ConstKind::Param(p) => Some(p.index),
+ _ => None,
+ },
+ };
+
+ // FIXME(eddyb) cache this (including computing `unsizing_params`)
+ // by putting it in a query; it would only need the `DefId` as it
+ // looks at declared field types, not anything substituted.
+
+ // The last field of the structure has to exist and contain type/const parameters.
+ let (tail_field, prefix_fields) =
+ def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?;
+ let tail_field_ty = tcx.bound_type_of(tail_field.did);
+
+ let mut unsizing_params = GrowableBitSet::new_empty();
+ for arg in tail_field_ty.0.walk() {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.insert(i);
+ }
+ }
+
+ // Ensure none of the other fields mention the parameters used
+ // in unsizing.
+ for field in prefix_fields {
+ for arg in tcx.type_of(field.did).walk() {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.remove(i);
+ }
+ }
+ }
+
+ if unsizing_params.is_empty() {
+ return Err(Unimplemented);
+ }
+
+ // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
+ let source_tail = tail_field_ty.subst(tcx, substs_a);
+ let target_tail = tail_field_ty.subst(tcx, substs_b);
+
+ // Check that the source struct with the target's
+ // unsizing parameters is equal to the target.
+ let substs = tcx.mk_substs(substs_a.iter().enumerate().map(|(i, k)| {
+ if unsizing_params.contains(i as u32) { substs_b[i] } else { k }
+ }));
+ let new_struct = tcx.mk_adt(def, substs);
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(target, new_struct)
+ .map_err(|_| Unimplemented)?;
+ nested.extend(obligations);
+
+ // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
+ nested.push(predicate_for_trait_def(
+ tcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.predicate.def_id(),
+ obligation.recursion_depth + 1,
+ source_tail,
+ &[target_tail.into()],
+ ));
+ }
+
+ // `(.., T)` -> `(.., U)`
+ (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
+ assert_eq!(tys_a.len(), tys_b.len());
+
+ // The last field of the tuple has to exist.
+ let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?;
+ let &b_last = tys_b.last().unwrap();
+
+ // Check that the source tuple with the target's
+ // last element is equal to the target.
+ let new_tuple = tcx.mk_tup(a_mid.iter().copied().chain(iter::once(b_last)));
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .eq(target, new_tuple)
+ .map_err(|_| Unimplemented)?;
+ nested.extend(obligations);
+
+ // Construct the nested `T: Unsize<U>` predicate.
+ nested.push(ensure_sufficient_stack(|| {
+ predicate_for_trait_def(
+ tcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.predicate.def_id(),
+ obligation.recursion_depth + 1,
+ a_last,
+ &[b_last.into()],
+ )
+ }));
+ }
+
+ _ => bug!(),
+ };
+
+ Ok(ImplSourceBuiltinData { nested })
+ }
+
+ fn confirm_const_destruct_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ impl_def_id: Option<DefId>,
+ ) -> Result<ImplSourceConstDestructData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop`
+ if !obligation.is_const() {
+ return Ok(ImplSourceConstDestructData { nested: vec![] });
+ }
+
+ let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
+
+ let tcx = self.tcx();
+ let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+
+ let mut nested = vec![];
+ let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+ // If we have a custom `impl const Drop`, then
+ // first check it like a regular impl candidate.
+ // This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand.
+ if let Some(impl_def_id) = impl_def_id {
+ let mut new_obligation = obligation.clone();
+ new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
+ trait_pred.trait_ref.def_id = drop_trait;
+ trait_pred
+ });
+ let substs = self.rematch_impl(impl_def_id, &new_obligation);
+ debug!(?substs, "impl substs");
+
+ let cause = obligation.derived_cause(|derived| {
+ ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+ derived,
+ impl_def_id,
+ span: obligation.cause.span,
+ }))
+ });
+ let obligations = ensure_sufficient_stack(|| {
+ self.vtable_impl(
+ impl_def_id,
+ substs,
+ &cause,
+ new_obligation.recursion_depth + 1,
+ new_obligation.param_env,
+ obligation.predicate,
+ )
+ });
+ nested.extend(obligations.nested);
+ }
+
+ // We want to confirm the ADT's fields if we have an ADT
+ let mut stack = match *self_ty.skip_binder().kind() {
+ ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(),
+ _ => vec![self_ty.skip_binder()],
+ };
+
+ while let Some(nested_ty) = stack.pop() {
+ match *nested_ty.kind() {
+ // We know these types are trivially drop
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::Str
+ | ty::RawPtr(_)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Foreign(_) => {}
+
+ // These types are built-in, so we can fast-track by registering
+ // nested predicates for their constituent type(s)
+ ty::Array(ty, _) | ty::Slice(ty) => {
+ stack.push(ty);
+ }
+ ty::Tuple(tys) => {
+ stack.extend(tys.iter());
+ }
+ ty::Closure(_, substs) => {
+ stack.push(substs.as_closure().tupled_upvars_ty());
+ }
+ ty::Generator(_, substs, _) => {
+ let generator = substs.as_generator();
+ stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
+ }
+ ty::GeneratorWitness(tys) => {
+ stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
+ }
+
+ // If we have a projection type, make sure to normalize it so we replace it
+ // with a fresh infer variable
+ ty::Projection(..) => {
+ let predicate = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ self_ty
+ .rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(LangItem::Destruct, None),
+ substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ .to_predicate(tcx),
+ &mut nested,
+ );
+
+ nested.push(Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ ));
+ }
+
+ // If we have any other type (e.g. an ADT), just register a nested obligation
+ // since it's either not `const Drop` (and we raise an error during selection),
+ // or it's an ADT (and we need to check for a custom impl during selection)
+ _ => {
+ let predicate = self_ty
+ .rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(LangItem::Destruct, None),
+ substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ .to_predicate(tcx);
+
+ nested.push(Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ ));
+ }
+ }
+ }
+
+ Ok(ImplSourceConstDestructData { nested })
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
new file mode 100644
index 000000000..c01ac1979
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -0,0 +1,2698 @@
+//! Candidate selection. See the [rustc dev guide] for more information on how this works.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
+
+use self::EvaluationResult::*;
+use self::SelectionCandidate::*;
+
+use super::coherence::{self, Conflict};
+use super::const_evaluatable;
+use super::project;
+use super::project::normalize_with_depth_to;
+use super::project::ProjectionTyObligation;
+use super::util;
+use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
+use super::wf;
+use super::{
+ ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation,
+ ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError,
+ SelectionResult, TraitObligation, TraitQueryMode,
+};
+
+use crate::infer::{InferCtxt, InferOk, TypeFreshener};
+use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::project::ProjectAndUnifyResult;
+use crate::traits::project::ProjectionCacheKeyExt;
+use crate::traits::ProjectionCacheKey;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
+use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::ty::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::relate::TypeRelation;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
+use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_span::symbol::sym;
+
+use std::cell::{Cell, RefCell};
+use std::cmp;
+use std::fmt::{self, Display};
+use std::iter;
+
+pub use rustc_middle::traits::select::*;
+
+mod candidate_assembly;
+mod confirmation;
+
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+pub enum IntercrateAmbiguityCause {
+ DownstreamCrate { trait_desc: String, self_desc: Option<String> },
+ UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> },
+ ReservationImpl { message: String },
+}
+
+impl IntercrateAmbiguityCause {
+ /// Emits notes when the overlap is caused by complex intercrate ambiguities.
+ /// See #23980 for details.
+ pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) {
+ err.note(&self.intercrate_ambiguity_hint());
+ }
+
+ pub fn intercrate_ambiguity_hint(&self) -> String {
+ match self {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => {
+ let self_desc = if let Some(ty) = self_desc {
+ format!(" for type `{}`", ty)
+ } else {
+ String::new()
+ };
+ format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
+ }
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => {
+ let self_desc = if let Some(ty) = self_desc {
+ format!(" for type `{}`", ty)
+ } else {
+ String::new()
+ };
+ format!(
+ "upstream crates may add a new impl of trait `{}`{} \
+ in future versions",
+ trait_desc, self_desc
+ )
+ }
+ IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(),
+ }
+ }
+}
+
+pub struct SelectionContext<'cx, 'tcx> {
+ infcx: &'cx InferCtxt<'cx, 'tcx>,
+
+ /// Freshener used specifically for entries on the obligation
+ /// stack. This ensures that all entries on the stack at one time
+ /// will have the same set of placeholder entries, which is
+ /// important for checking for trait bounds that recursively
+ /// require themselves.
+ freshener: TypeFreshener<'cx, 'tcx>,
+
+ /// During coherence we have to assume that other crates may add
+ /// additional impls which we currently don't know about.
+ ///
+ /// To deal with this evaluation should be conservative
+ /// and consider the possibility of impls from outside this crate.
+ /// This comes up primarily when resolving ambiguity. Imagine
+ /// there is some trait reference `$0: Bar` where `$0` is an
+ /// inference variable. If `intercrate` is true, then we can never
+ /// say for sure that this reference is not implemented, even if
+ /// there are *no impls at all for `Bar`*, because `$0` could be
+ /// bound to some type that in a downstream crate that implements
+ /// `Bar`.
+ ///
+ /// Outside of coherence we set this to false because we are only
+ /// interested in types that the user could actually have written.
+ /// In other words, we consider `$0: Bar` to be unimplemented if
+ /// there is no type that the user could *actually name* that
+ /// would satisfy it. This avoids crippling inference, basically.
+ intercrate: bool,
+ /// If `intercrate` is set, we remember predicates which were
+ /// considered ambiguous because of impls potentially added in other crates.
+ /// This is used in coherence to give improved diagnostics.
+ /// We don't do his until we detect a coherence error because it can
+ /// lead to false overflow results (#47139) and because always
+ /// computing it may negatively impact performance.
+ intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause>>,
+
+ /// The mode that trait queries run in, which informs our error handling
+ /// policy. In essence, canonicalized queries need their errors propagated
+ /// rather than immediately reported because we do not have accurate spans.
+ query_mode: TraitQueryMode,
+}
+
+// A stack that walks back up the stack frame.
+struct TraitObligationStack<'prev, 'tcx> {
+ obligation: &'prev TraitObligation<'tcx>,
+
+ /// The trait predicate from `obligation` but "freshened" with the
+ /// selection-context's freshener. Used to check for recursion.
+ fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+
+ /// Starts out equal to `depth` -- if, during evaluation, we
+ /// encounter a cycle, then we will set this flag to the minimum
+ /// depth of that cycle for all participants in the cycle. These
+ /// participants will then forego caching their results. This is
+ /// not the most efficient solution, but it addresses #60010. The
+ /// problem we are trying to prevent:
+ ///
+ /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
+ /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
+ /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok)
+ ///
+ /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait`
+ /// is `EvaluatedToOk`; this is because they were only considered
+ /// ok on the premise that if `A: AutoTrait` held, but we indeed
+ /// encountered a problem (later on) with `A: AutoTrait. So we
+ /// currently set a flag on the stack node for `B: AutoTrait` (as
+ /// well as the second instance of `A: AutoTrait`) to suppress
+ /// caching.
+ ///
+ /// This is a simple, targeted fix. A more-performant fix requires
+ /// deeper changes, but would permit more caching: we could
+ /// basically defer caching until we have fully evaluated the
+ /// tree, and then cache the entire tree at once. In any case, the
+ /// performance impact here shouldn't be so horrible: every time
+ /// this is hit, we do cache at least one trait, so we only
+ /// evaluate each member of a cycle up to N times, where N is the
+ /// length of the cycle. This means the performance impact is
+ /// bounded and we shouldn't have any terrible worst-cases.
+ reached_depth: Cell<usize>,
+
+ previous: TraitObligationStackList<'prev, 'tcx>,
+
+ /// The number of parent frames plus one (thus, the topmost frame has depth 1).
+ depth: usize,
+
+ /// The depth-first number of this node in the search graph -- a
+ /// pre-order index. Basically, a freshly incremented counter.
+ dfn: usize,
+}
+
+struct SelectionCandidateSet<'tcx> {
+ // A list of candidates that definitely apply to the current
+ // obligation (meaning: types unify).
+ vec: Vec<SelectionCandidate<'tcx>>,
+
+ // If `true`, then there were candidates that might or might
+ // not have applied, but we couldn't tell. This occurs when some
+ // of the input types are type variables, in which case there are
+ // various "builtin" rules that might or might not trigger.
+ ambiguous: bool,
+}
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+struct EvaluatedCandidate<'tcx> {
+ candidate: SelectionCandidate<'tcx>,
+ evaluation: EvaluationResult,
+}
+
+/// When does the builtin impl for `T: Trait` apply?
+#[derive(Debug)]
+enum BuiltinImplConditions<'tcx> {
+ /// The impl is conditional on `T1, T2, ...: Trait`.
+ Where(ty::Binder<'tcx, Vec<Ty<'tcx>>>),
+ /// There is no built-in impl. There may be some other
+ /// candidate (a where-clause or user-defined impl).
+ None,
+ /// It is unknown whether there is an impl.
+ Ambiguous,
+}
+
+impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+ pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
+ SelectionContext {
+ infcx,
+ freshener: infcx.freshener_keep_static(),
+ intercrate: false,
+ intercrate_ambiguity_causes: None,
+ query_mode: TraitQueryMode::Standard,
+ }
+ }
+
+ pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
+ SelectionContext {
+ infcx,
+ freshener: infcx.freshener_keep_static(),
+ intercrate: true,
+ intercrate_ambiguity_causes: None,
+ query_mode: TraitQueryMode::Standard,
+ }
+ }
+
+ pub fn with_query_mode(
+ infcx: &'cx InferCtxt<'cx, 'tcx>,
+ query_mode: TraitQueryMode,
+ ) -> SelectionContext<'cx, 'tcx> {
+ debug!(?query_mode, "with_query_mode");
+ SelectionContext {
+ infcx,
+ freshener: infcx.freshener_keep_static(),
+ intercrate: false,
+ intercrate_ambiguity_causes: None,
+ query_mode,
+ }
+ }
+
+ /// Enables tracking of intercrate ambiguity causes. See
+ /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
+ pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
+ assert!(self.intercrate);
+ assert!(self.intercrate_ambiguity_causes.is_none());
+ self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
+ debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
+ }
+
+ /// Gets the intercrate ambiguity causes collected since tracking
+ /// was enabled and disables tracking at the same time. If
+ /// tracking is not enabled, just returns an empty vector.
+ pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
+ assert!(self.intercrate);
+ self.intercrate_ambiguity_causes.take().unwrap_or_default()
+ }
+
+ pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
+ self.infcx
+ }
+
+ pub fn tcx(&self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ pub fn is_intercrate(&self) -> bool {
+ self.intercrate
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Selection
+ //
+ // The selection phase tries to identify *how* an obligation will
+ // be resolved. For example, it will identify which impl or
+ // parameter bound is to be used. The process can be inconclusive
+ // if the self type in the obligation is not fully inferred. Selection
+ // can result in an error in one of two ways:
+ //
+ // 1. If no applicable impl or parameter bound can be found.
+ // 2. If the output type parameters in the obligation do not match
+ // those specified by the impl/bound. For example, if the obligation
+ // is `Vec<Foo>: Iterable<Bar>`, but the impl specifies
+ // `impl<T> Iterable<T> for Vec<T>`, than an error would result.
+
+ /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
+ /// type environment by performing unification.
+ #[instrument(level = "debug", skip(self))]
+ pub fn select(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, Selection<'tcx>> {
+ let candidate = match self.select_from_obligation(obligation) {
+ Err(SelectionError::Overflow(OverflowError::Canonical)) => {
+ // In standard mode, overflow must have been caught and reported
+ // earlier.
+ assert!(self.query_mode == TraitQueryMode::Canonical);
+ return Err(SelectionError::Overflow(OverflowError::Canonical));
+ }
+ Err(SelectionError::Ambiguous(_)) => {
+ return Ok(None);
+ }
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(None) => {
+ return Ok(None);
+ }
+ Ok(Some(candidate)) => candidate,
+ };
+
+ match self.confirm_candidate(obligation, candidate) {
+ Err(SelectionError::Overflow(OverflowError::Canonical)) => {
+ assert!(self.query_mode == TraitQueryMode::Canonical);
+ Err(SelectionError::Overflow(OverflowError::Canonical))
+ }
+ Err(e) => Err(e),
+ Ok(candidate) => {
+ debug!(?candidate, "confirmed");
+ Ok(Some(candidate))
+ }
+ }
+ }
+
+ pub(crate) fn select_from_obligation(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+ let pec = &ProvisionalEvaluationCache::default();
+ let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+ self.candidate_from_obligation(&stack)
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // EVALUATION
+ //
+ // Tests whether an obligation can be selected or whether an impl
+ // can be applied to particular types. It skips the "confirmation"
+ // step and hence completely ignores output type parameters.
+ //
+ // The result is "true" if the obligation *may* hold and "false" if
+ // we can be sure it does not.
+
+ /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
+ pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
+ debug!(?obligation, "predicate_may_hold_fatal");
+
+ // This fatal query is a stopgap that should only be used in standard mode,
+ // where we do not expect overflow to be propagated.
+ assert!(self.query_mode == TraitQueryMode::Standard);
+
+ self.evaluate_root_obligation(obligation)
+ .expect("Overflow should be caught earlier in standard query mode")
+ .may_apply()
+ }
+
+ /// Evaluates whether the obligation `obligation` can be satisfied
+ /// and returns an `EvaluationResult`. This is meant for the
+ /// *initial* call.
+ pub fn evaluate_root_obligation(
+ &mut self,
+ obligation: &PredicateObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ self.evaluation_probe(|this| {
+ this.evaluate_predicate_recursively(
+ TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
+ obligation.clone(),
+ )
+ })
+ }
+
+ fn evaluation_probe(
+ &mut self,
+ op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> {
+ let result = op(self)?;
+
+ match self.infcx.leak_check(true, snapshot) {
+ Ok(()) => {}
+ Err(_) => return Ok(EvaluatedToErr),
+ }
+
+ if self.infcx.opaque_types_added_in_snapshot(snapshot) {
+ return Ok(result.max(EvaluatedToOkModuloOpaqueTypes));
+ }
+
+ match self.infcx.region_constraints_added_in_snapshot(snapshot) {
+ None => Ok(result),
+ Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
+ }
+ })
+ }
+
+ /// Evaluates the predicates in `predicates` recursively. Note that
+ /// this applies projections in the predicates, and therefore
+ /// is run within an inference probe.
+ #[instrument(skip(self, stack), level = "debug")]
+ fn evaluate_predicates_recursively<'o, I>(
+ &mut self,
+ stack: TraitObligationStackList<'o, 'tcx>,
+ predicates: I,
+ ) -> Result<EvaluationResult, OverflowError>
+ where
+ I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
+ {
+ let mut result = EvaluatedToOk;
+ for obligation in predicates {
+ let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
+ if let EvaluatedToErr = eval {
+ // fast-path - EvaluatedToErr is the top of the lattice,
+ // so we don't need to look on the other predicates.
+ return Ok(EvaluatedToErr);
+ } else {
+ result = cmp::max(result, eval);
+ }
+ }
+ Ok(result)
+ }
+
+ #[instrument(
+ level = "debug",
+ skip(self, previous_stack),
+ fields(previous_stack = ?previous_stack.head())
+ )]
+ fn evaluate_predicate_recursively<'o>(
+ &mut self,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
+ obligation: PredicateObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ // `previous_stack` stores a `TraitObligation`, while `obligation` is
+ // a `PredicateObligation`. These are distinct types, so we can't
+ // use any `Option` combinator method that would force them to be
+ // the same.
+ match previous_stack.head() {
+ Some(h) => self.check_recursion_limit(&obligation, h.obligation)?,
+ None => self.check_recursion_limit(&obligation, &obligation)?,
+ }
+
+ let result = ensure_sufficient_stack(|| {
+ let bound_predicate = obligation.predicate.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(t) => {
+ let t = bound_predicate.rebind(t);
+ debug_assert!(!t.has_escaping_bound_vars());
+ let obligation = obligation.with(t);
+ self.evaluate_trait_predicate_recursively(previous_stack, obligation)
+ }
+
+ ty::PredicateKind::Subtype(p) => {
+ let p = bound_predicate.rebind(p);
+ // Does this code ever run?
+ match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
+ Some(Ok(InferOk { mut obligations, .. })) => {
+ self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+ self.evaluate_predicates_recursively(
+ previous_stack,
+ obligations.into_iter(),
+ )
+ }
+ Some(Err(_)) => Ok(EvaluatedToErr),
+ None => Ok(EvaluatedToAmbig),
+ }
+ }
+
+ ty::PredicateKind::Coerce(p) => {
+ let p = bound_predicate.rebind(p);
+ // Does this code ever run?
+ match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
+ Some(Ok(InferOk { mut obligations, .. })) => {
+ self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+ self.evaluate_predicates_recursively(
+ previous_stack,
+ obligations.into_iter(),
+ )
+ }
+ Some(Err(_)) => Ok(EvaluatedToErr),
+ None => Ok(EvaluatedToAmbig),
+ }
+ }
+
+ ty::PredicateKind::WellFormed(arg) => {
+ // So, there is a bit going on here. First, `WellFormed` predicates
+ // are coinductive, like trait predicates with auto traits.
+ // This means that we need to detect if we have recursively
+ // evaluated `WellFormed(X)`. Otherwise, we would run into
+ // a "natural" overflow error.
+ //
+ // Now, the next question is whether we need to do anything
+ // special with caching. Considering the following tree:
+ // - `WF(Foo<T>)`
+ // - `Bar<T>: Send`
+ // - `WF(Foo<T>)`
+ // - `Foo<T>: Trait`
+ // In this case, the innermost `WF(Foo<T>)` should return
+ // `EvaluatedToOk`, since it's coinductive. Then if
+ // `Bar<T>: Send` is resolved to `EvaluatedToOk`, it can be
+ // inserted into a cache (because without thinking about `WF`
+ // goals, it isn't in a cycle). If `Foo<T>: Trait` later doesn't
+ // hold, then `Bar<T>: Send` shouldn't hold. Therefore, we
+ // *do* need to keep track of coinductive cycles.
+
+ let cache = previous_stack.cache;
+ let dfn = cache.next_dfn();
+
+ for stack_arg in previous_stack.cache.wf_args.borrow().iter().rev() {
+ if stack_arg.0 != arg {
+ continue;
+ }
+ debug!("WellFormed({:?}) on stack", arg);
+ if let Some(stack) = previous_stack.head {
+ // Okay, let's imagine we have two different stacks:
+ // `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait`
+ // `WF(T) -> T: NonAutoTrait -> WF(T)`
+ // Because of this, we need to check that all
+ // predicates between the WF goals are coinductive.
+ // Otherwise, we can say that `T: NonAutoTrait` is
+ // true.
+ // Let's imagine we have a predicate stack like
+ // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto
+ // depth ^1 ^2 ^3
+ // and the current predicate is `WF(T)`. `wf_args`
+ // would contain `(T, 1)`. We want to check all
+ // trait predicates greater than `1`. The previous
+ // stack would be `T: Auto`.
+ let cycle = stack.iter().take_while(|s| s.depth > stack_arg.1);
+ let tcx = self.tcx();
+ let cycle =
+ cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
+ if self.coinductive_match(cycle) {
+ stack.update_reached_depth(stack_arg.1);
+ return Ok(EvaluatedToOk);
+ } else {
+ return Ok(EvaluatedToRecur);
+ }
+ }
+ return Ok(EvaluatedToOk);
+ }
+
+ match wf::obligations(
+ self.infcx,
+ obligation.param_env,
+ obligation.cause.body_id,
+ obligation.recursion_depth + 1,
+ arg,
+ obligation.cause.span,
+ ) {
+ Some(mut obligations) => {
+ self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+
+ cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
+ let result =
+ self.evaluate_predicates_recursively(previous_stack, obligations);
+ cache.wf_args.borrow_mut().pop();
+
+ let result = result?;
+
+ if !result.must_apply_modulo_regions() {
+ cache.on_failure(dfn);
+ }
+
+ cache.on_completion(dfn);
+
+ Ok(result)
+ }
+ None => Ok(EvaluatedToAmbig),
+ }
+ }
+
+ ty::PredicateKind::TypeOutlives(pred) => {
+ // A global type with no late-bound regions can only
+ // contain the "'static" lifetime (any other lifetime
+ // would either be late-bound or local), so it is guaranteed
+ // to outlive any other lifetime
+ if pred.0.is_global() && !pred.0.has_late_bound_regions() {
+ Ok(EvaluatedToOk)
+ } else {
+ Ok(EvaluatedToOkModuloRegions)
+ }
+ }
+
+ ty::PredicateKind::RegionOutlives(..) => {
+ // We do not consider region relationships when evaluating trait matches.
+ Ok(EvaluatedToOkModuloRegions)
+ }
+
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ if self.tcx().is_object_safe(trait_def_id) {
+ Ok(EvaluatedToOk)
+ } else {
+ Ok(EvaluatedToErr)
+ }
+ }
+
+ ty::PredicateKind::Projection(data) => {
+ let data = bound_predicate.rebind(data);
+ let project_obligation = obligation.with(data);
+ match project::poly_project_and_unify_type(self, &project_obligation) {
+ ProjectAndUnifyResult::Holds(mut subobligations) => {
+ 'compute_res: {
+ // If we've previously marked this projection as 'complete', then
+ // use the final cached result (either `EvaluatedToOk` or
+ // `EvaluatedToOkModuloRegions`), and skip re-evaluating the
+ // sub-obligations.
+ if let Some(key) =
+ ProjectionCacheKey::from_poly_projection_predicate(self, data)
+ {
+ if let Some(cached_res) = self
+ .infcx
+ .inner
+ .borrow_mut()
+ .projection_cache()
+ .is_complete(key)
+ {
+ break 'compute_res Ok(cached_res);
+ }
+ }
+
+ self.add_depth(
+ subobligations.iter_mut(),
+ obligation.recursion_depth,
+ );
+ let res = self.evaluate_predicates_recursively(
+ previous_stack,
+ subobligations,
+ );
+ if let Ok(eval_rslt) = res
+ && (eval_rslt == EvaluatedToOk || eval_rslt == EvaluatedToOkModuloRegions)
+ && let Some(key) =
+ ProjectionCacheKey::from_poly_projection_predicate(
+ self, data,
+ )
+ {
+ // If the result is something that we can cache, then mark this
+ // entry as 'complete'. This will allow us to skip evaluating the
+ // subobligations at all the next time we evaluate the projection
+ // predicate.
+ self.infcx
+ .inner
+ .borrow_mut()
+ .projection_cache()
+ .complete(key, eval_rslt);
+ }
+ res
+ }
+ }
+ ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
+ ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur),
+ ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
+ }
+ }
+
+ ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
+ match self.infcx.closure_kind(closure_substs) {
+ Some(closure_kind) => {
+ if closure_kind.extends(kind) {
+ Ok(EvaluatedToOk)
+ } else {
+ Ok(EvaluatedToErr)
+ }
+ }
+ None => Ok(EvaluatedToAmbig),
+ }
+ }
+
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ match const_evaluatable::is_const_evaluatable(
+ self.infcx,
+ uv,
+ obligation.param_env,
+ obligation.cause.span,
+ ) {
+ Ok(()) => Ok(EvaluatedToOk),
+ Err(NotConstEvaluatable::MentionsInfer) => Ok(EvaluatedToAmbig),
+ Err(NotConstEvaluatable::MentionsParam) => Ok(EvaluatedToErr),
+ Err(_) => Ok(EvaluatedToErr),
+ }
+ }
+
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
+
+ if self.tcx().features().generic_const_exprs {
+ // FIXME: we probably should only try to unify abstract constants
+ // if the constants depend on generic parameters.
+ //
+ // Let's just see where this breaks :shrug:
+ if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+ (c1.kind(), c2.kind())
+ {
+ if self.infcx.try_unify_abstract_consts(
+ a.shrink(),
+ b.shrink(),
+ obligation.param_env,
+ ) {
+ return Ok(EvaluatedToOk);
+ }
+ }
+ }
+
+ let evaluate = |c: ty::Const<'tcx>| {
+ if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
+ match self.infcx.try_const_eval_resolve(
+ obligation.param_env,
+ unevaluated,
+ c.ty(),
+ Some(obligation.cause.span),
+ ) {
+ Ok(val) => Ok(val),
+ Err(e) => Err(e),
+ }
+ } else {
+ Ok(c)
+ }
+ };
+
+ match (evaluate(c1), evaluate(c2)) {
+ (Ok(c1), Ok(c2)) => {
+ match self
+ .infcx()
+ .at(&obligation.cause, obligation.param_env)
+ .eq(c1, c2)
+ {
+ Ok(_) => Ok(EvaluatedToOk),
+ Err(_) => Ok(EvaluatedToErr),
+ }
+ }
+ (Err(ErrorHandled::Reported(_)), _)
+ | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr),
+ (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
+ span_bug!(
+ obligation.cause.span(),
+ "ConstEquate: const_eval_resolve returned an unexpected error"
+ )
+ }
+ (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+ if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+ Ok(EvaluatedToAmbig)
+ } else {
+ // Two different constants using generic parameters ~> error.
+ Ok(EvaluatedToErr)
+ }
+ }
+ }
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for chalk")
+ }
+ }
+ });
+
+ debug!("finished: {:?} from {:?}", result, obligation);
+
+ result
+ }
+
+ #[instrument(skip(self, previous_stack), level = "debug")]
+ fn evaluate_trait_predicate_recursively<'o>(
+ &mut self,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
+ mut obligation: TraitObligation<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ if !self.intercrate
+ && obligation.is_global()
+ && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
+ {
+ // If a param env has no global bounds, global obligations do not
+ // depend on its particular value in order to work, so we can clear
+ // out the param env and get better caching.
+ debug!("in global");
+ obligation.param_env = obligation.param_env.without_caller_bounds();
+ }
+
+ let stack = self.push_stack(previous_stack, &obligation);
+ let mut fresh_trait_pred = stack.fresh_trait_pred;
+ let mut param_env = obligation.param_env;
+
+ fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| {
+ pred.remap_constness(&mut param_env);
+ pred
+ });
+
+ debug!(?fresh_trait_pred);
+
+ // If a trait predicate is in the (local or global) evaluation cache,
+ // then we know it holds without cycles.
+ if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) {
+ debug!(?result, "CACHE HIT");
+ return Ok(result);
+ }
+
+ if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) {
+ debug!(?result, "PROVISIONAL CACHE HIT");
+ stack.update_reached_depth(result.reached_depth);
+ return Ok(result.result);
+ }
+
+ // Check if this is a match for something already on the
+ // stack. If so, we don't want to insert the result into the
+ // main cache (it is cycle dependent) nor the provisional
+ // cache (which is meant for things that have completed but
+ // for a "backedge" -- this result *is* the backedge).
+ if let Some(cycle_result) = self.check_evaluation_cycle(&stack) {
+ return Ok(cycle_result);
+ }
+
+ let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
+ let result = result?;
+
+ if !result.must_apply_modulo_regions() {
+ stack.cache().on_failure(stack.dfn);
+ }
+
+ let reached_depth = stack.reached_depth.get();
+ if reached_depth >= stack.depth {
+ debug!(?result, "CACHE MISS");
+ self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
+ stack.cache().on_completion(stack.dfn);
+ } else {
+ debug!(?result, "PROVISIONAL");
+ debug!(
+ "caching provisionally because {:?} \
+ is a cycle participant (at depth {}, reached depth {})",
+ fresh_trait_pred, stack.depth, reached_depth,
+ );
+
+ stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
+ }
+
+ Ok(result)
+ }
+
+ /// If there is any previous entry on the stack that precisely
+ /// matches this obligation, then we can assume that the
+ /// obligation is satisfied for now (still all other conditions
+ /// must be met of course). One obvious case this comes up is
+ /// marker traits like `Send`. Think of a linked list:
+ ///
+ /// struct List<T> { data: T, next: Option<Box<List<T>>> }
+ ///
+ /// `Box<List<T>>` will be `Send` if `T` is `Send` and
+ /// `Option<Box<List<T>>>` is `Send`, and in turn
+ /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is
+ /// `Send`.
+ ///
+ /// Note that we do this comparison using the `fresh_trait_ref`
+ /// fields. Because these have all been freshened using
+ /// `self.freshener`, we can be sure that (a) this will not
+ /// affect the inferencer state and (b) that if we see two
+ /// fresh regions with the same index, they refer to the same
+ /// unbound type variable.
+ fn check_evaluation_cycle(
+ &mut self,
+ stack: &TraitObligationStack<'_, 'tcx>,
+ ) -> Option<EvaluationResult> {
+ if let Some(cycle_depth) = stack
+ .iter()
+ .skip(1) // Skip top-most frame.
+ .find(|prev| {
+ stack.obligation.param_env == prev.obligation.param_env
+ && stack.fresh_trait_pred == prev.fresh_trait_pred
+ })
+ .map(|stack| stack.depth)
+ {
+ debug!("evaluate_stack --> recursive at depth {}", cycle_depth);
+
+ // If we have a stack like `A B C D E A`, where the top of
+ // the stack is the final `A`, then this will iterate over
+ // `A, E, D, C, B` -- i.e., all the participants apart
+ // from the cycle head. We mark them as participating in a
+ // cycle. This suppresses caching for those nodes. See
+ // `in_cycle` field for more details.
+ stack.update_reached_depth(cycle_depth);
+
+ // Subtle: when checking for a coinductive cycle, we do
+ // not compare using the "freshened trait refs" (which
+ // have erased regions) but rather the fully explicit
+ // trait refs. This is important because it's only a cycle
+ // if the regions match exactly.
+ let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
+ let tcx = self.tcx();
+ let cycle = cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
+ if self.coinductive_match(cycle) {
+ debug!("evaluate_stack --> recursive, coinductive");
+ Some(EvaluatedToOk)
+ } else {
+ debug!("evaluate_stack --> recursive, inductive");
+ Some(EvaluatedToRecur)
+ }
+ } else {
+ None
+ }
+ }
+
+ fn evaluate_stack<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ // In intercrate mode, whenever any of the generics are unbound,
+ // there can always be an impl. Even if there are no impls in
+ // this crate, perhaps the type would be unified with
+ // something from another crate that does provide an impl.
+ //
+ // In intra mode, we must still be conservative. The reason is
+ // that we want to avoid cycles. Imagine an impl like:
+ //
+ // impl<T:Eq> Eq for Vec<T>
+ //
+ // and a trait reference like `$0 : Eq` where `$0` is an
+ // unbound variable. When we evaluate this trait-reference, we
+ // will unify `$0` with `Vec<$1>` (for some fresh variable
+ // `$1`), on the condition that `$1 : Eq`. We will then wind
+ // up with many candidates (since that are other `Eq` impls
+ // that apply) and try to winnow things down. This results in
+ // a recursive evaluation that `$1 : Eq` -- as you can
+ // imagine, this is just where we started. To avoid that, we
+ // check for unbound variables and return an ambiguous (hence possible)
+ // match if we've seen this trait before.
+ //
+ // This suffices to allow chains like `FnMut` implemented in
+ // terms of `Fn` etc, but we could probably make this more
+ // precise still.
+ let unbound_input_types =
+ stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh());
+
+ if stack.obligation.polarity() != ty::ImplPolarity::Negative {
+ // This check was an imperfect workaround for a bug in the old
+ // intercrate mode; it should be removed when that goes away.
+ if unbound_input_types && self.intercrate {
+ debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let cause = with_no_trimmed_paths!({
+ IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc: trait_ref.print_only_trait_path().to_string(),
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ }
+ });
+
+ debug!(?cause, "evaluate_stack: pushing cause");
+ self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
+ }
+ }
+ }
+ return Ok(EvaluatedToAmbig);
+ }
+ }
+
+ if unbound_input_types
+ && stack.iter().skip(1).any(|prev| {
+ stack.obligation.param_env == prev.obligation.param_env
+ && self.match_fresh_trait_refs(
+ stack.fresh_trait_pred,
+ prev.fresh_trait_pred,
+ prev.obligation.param_env,
+ )
+ })
+ {
+ debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
+ return Ok(EvaluatedToUnknown);
+ }
+
+ match self.candidate_from_obligation(stack) {
+ Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+ Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
+ Ok(None) => Ok(EvaluatedToAmbig),
+ Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
+ Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
+ Err(..) => Ok(EvaluatedToErr),
+ }
+ }
+
+ /// For defaulted traits, we use a co-inductive strategy to solve, so
+ /// that recursion is ok. This routine returns `true` if the top of the
+ /// stack (`cycle[0]`):
+ ///
+ /// - is a defaulted trait,
+ /// - it also appears in the backtrace at some position `X`,
+ /// - all the predicates at positions `X..` between `X` and the top are
+ /// also defaulted traits.
+ pub(crate) fn coinductive_match<I>(&mut self, mut cycle: I) -> bool
+ where
+ I: Iterator<Item = ty::Predicate<'tcx>>,
+ {
+ cycle.all(|predicate| self.coinductive_predicate(predicate))
+ }
+
+ fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
+ let result = match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
+ ty::PredicateKind::WellFormed(_) => true,
+ _ => false,
+ };
+ debug!(?predicate, ?result, "coinductive_predicate");
+ result
+ }
+
+ /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
+ /// obligations are met. Returns whether `candidate` remains viable after this further
+ /// scrutiny.
+ #[instrument(
+ level = "debug",
+ skip(self, stack),
+ fields(depth = stack.obligation.recursion_depth)
+ )]
+ fn evaluate_candidate<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ candidate: &SelectionCandidate<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ let mut result = self.evaluation_probe(|this| {
+ let candidate = (*candidate).clone();
+ match this.confirm_candidate(stack.obligation, candidate) {
+ Ok(selection) => {
+ debug!(?selection);
+ this.evaluate_predicates_recursively(
+ stack.list(),
+ selection.nested_obligations().into_iter(),
+ )
+ }
+ Err(..) => Ok(EvaluatedToErr),
+ }
+ })?;
+
+ // If we erased any lifetimes, then we want to use
+ // `EvaluatedToOkModuloRegions` instead of `EvaluatedToOk`
+ // as your final result. The result will be cached using
+ // the freshened trait predicate as a key, so we need
+ // our result to be correct by *any* choice of original lifetimes,
+ // not just the lifetime choice for this particular (non-erased)
+ // predicate.
+ // See issue #80691
+ if stack.fresh_trait_pred.has_erased_regions() {
+ result = result.max(EvaluatedToOkModuloRegions);
+ }
+
+ debug!(?result);
+ Ok(result)
+ }
+
+ fn check_evaluation_cache(
+ &self,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> Option<EvaluationResult> {
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return None;
+ }
+
+ let tcx = self.tcx();
+ if self.can_use_global_caches(param_env) {
+ if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) {
+ return Some(res);
+ }
+ }
+ self.infcx.evaluation_cache.get(&(param_env, trait_pred), tcx)
+ }
+
+ fn insert_evaluation_cache(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ dep_node: DepNodeIndex,
+ result: EvaluationResult,
+ ) {
+ // Avoid caching results that depend on more than just the trait-ref
+ // - the stack can create recursion.
+ if result.is_stack_dependent() {
+ return;
+ }
+
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return;
+ }
+
+ if self.can_use_global_caches(param_env) {
+ if !trait_pred.needs_infer() {
+ debug!(?trait_pred, ?result, "insert_evaluation_cache global");
+ // This may overwrite the cache with the same value
+ // FIXME: Due to #50507 this overwrites the different values
+ // This should be changed to use HashMapExt::insert_same
+ // when that is fixed
+ self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result);
+ return;
+ }
+ }
+
+ debug!(?trait_pred, ?result, "insert_evaluation_cache");
+ self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
+ }
+
+ /// For various reasons, it's possible for a subobligation
+ /// to have a *lower* recursion_depth than the obligation used to create it.
+ /// Projection sub-obligations may be returned from the projection cache,
+ /// which results in obligations with an 'old' `recursion_depth`.
+ /// Additionally, methods like `InferCtxt.subtype_predicate` produce
+ /// subobligations without taking in a 'parent' depth, causing the
+ /// generated subobligations to have a `recursion_depth` of `0`.
+ ///
+ /// To ensure that obligation_depth never decreases, we force all subobligations
+ /// to have at least the depth of the original obligation.
+ fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
+ &self,
+ it: I,
+ min_depth: usize,
+ ) {
+ it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
+ }
+
+ fn check_recursion_depth<T: Display + TypeFoldable<'tcx>>(
+ &self,
+ depth: usize,
+ error_obligation: &Obligation<'tcx, T>,
+ ) -> Result<(), OverflowError> {
+ if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
+ match self.query_mode {
+ TraitQueryMode::Standard => {
+ if self.infcx.is_tainted_by_errors() {
+ return Err(OverflowError::Error(
+ ErrorGuaranteed::unchecked_claim_error_was_emitted(),
+ ));
+ }
+ self.infcx.report_overflow_error(error_obligation, true);
+ }
+ TraitQueryMode::Canonical => {
+ return Err(OverflowError::Canonical);
+ }
+ }
+ }
+ Ok(())
+ }
+
+ /// Checks that the recursion limit has not been exceeded.
+ ///
+ /// The weird return type of this function allows it to be used with the `try` (`?`)
+ /// operator within certain functions.
+ #[inline(always)]
+ fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>(
+ &self,
+ obligation: &Obligation<'tcx, T>,
+ error_obligation: &Obligation<'tcx, V>,
+ ) -> Result<(), OverflowError> {
+ self.check_recursion_depth(obligation.recursion_depth, error_obligation)
+ }
+
+ fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
+ where
+ OP: FnOnce(&mut Self) -> R,
+ {
+ let (result, dep_node) =
+ self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self));
+ self.tcx().dep_graph.read_index(dep_node);
+ (result, dep_node)
+ }
+
+ /// filter_impls filters constant trait obligations and candidates that have a positive impl
+ /// for a negative goal and a negative impl for a positive goal
+ #[instrument(level = "debug", skip(self))]
+ fn filter_impls(
+ &mut self,
+ candidates: Vec<SelectionCandidate<'tcx>>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Vec<SelectionCandidate<'tcx>> {
+ let tcx = self.tcx();
+ let mut result = Vec::with_capacity(candidates.len());
+
+ for candidate in candidates {
+ // Respect const trait obligations
+ if obligation.is_const() {
+ match candidate {
+ // const impl
+ ImplCandidate(def_id) if tcx.constness(def_id) == hir::Constness::Const => {}
+ // const param
+ ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
+ // auto trait impl
+ AutoImplCandidate(..) => {}
+ // generator, this will raise error in other places
+ // or ignore error with const_async_blocks feature
+ GeneratorCandidate => {}
+ // FnDef where the function is const
+ FnPointerCandidate { is_const: true } => {}
+ ConstDestructCandidate(_) => {}
+ _ => {
+ // reject all other types of candidates
+ continue;
+ }
+ }
+ }
+
+ if let ImplCandidate(def_id) = candidate {
+ if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+ || obligation.polarity() == tcx.impl_polarity(def_id)
+ {
+ result.push(candidate);
+ }
+ } else {
+ result.push(candidate);
+ }
+ }
+
+ result
+ }
+
+ /// filter_reservation_impls filter reservation impl for any goal as ambiguous
+ #[instrument(level = "debug", skip(self))]
+ fn filter_reservation_impls(
+ &mut self,
+ candidate: SelectionCandidate<'tcx>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ let tcx = self.tcx();
+ // Treat reservation impls as ambiguity.
+ if let ImplCandidate(def_id) = candidate {
+ if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
+ if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
+ let value = tcx
+ .get_attr(def_id, sym::rustc_reservation_impl)
+ .and_then(|a| a.value_str());
+ if let Some(value) = value {
+ debug!(
+ "filter_reservation_impls: \
+ reservation impl ambiguity on {:?}",
+ def_id
+ );
+ intercrate_ambiguity_clauses.insert(
+ IntercrateAmbiguityCause::ReservationImpl {
+ message: value.to_string(),
+ },
+ );
+ }
+ }
+ return Ok(None);
+ }
+ }
+ Ok(Some(candidate))
+ }
+
+ fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
+ debug!("is_knowable(intercrate={:?})", self.intercrate);
+
+ if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
+ return None;
+ }
+
+ let obligation = &stack.obligation;
+ let predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
+
+ // Okay to skip binder because of the nature of the
+ // trait-ref-is-knowable check, which does not care about
+ // bound regions.
+ let trait_ref = predicate.skip_binder().trait_ref;
+
+ coherence::trait_ref_is_knowable(self.tcx(), trait_ref)
+ }
+
+ /// Returns `true` if the global caches can be used.
+ fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
+ // If there are any inference variables in the `ParamEnv`, then we
+ // always use a cache local to this particular scope. Otherwise, we
+ // switch to a global cache.
+ if param_env.needs_infer() {
+ return false;
+ }
+
+ // Avoid using the master cache during coherence and just rely
+ // on the local cache. This effectively disables caching
+ // during coherence. It is really just a simplification to
+ // avoid us having to fear that coherence results "pollute"
+ // the master cache. Since coherence executes pretty quickly,
+ // it's not worth going to more trouble to increase the
+ // hit-rate, I don't think.
+ if self.intercrate {
+ return false;
+ }
+
+ // Otherwise, we can use the global cache.
+ true
+ }
+
+ fn check_candidate_cache(
+ &mut self,
+ mut param_env: ty::ParamEnv<'tcx>,
+ cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return None;
+ }
+ let tcx = self.tcx();
+ let mut pred = cache_fresh_trait_pred.skip_binder();
+ pred.remap_constness(&mut param_env);
+
+ if self.can_use_global_caches(param_env) {
+ if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) {
+ return Some(res);
+ }
+ }
+ self.infcx.selection_cache.get(&(param_env, pred), tcx)
+ }
+
+ /// Determines whether can we safely cache the result
+ /// of selecting an obligation. This is almost always `true`,
+ /// except when dealing with certain `ParamCandidate`s.
+ ///
+ /// Ordinarily, a `ParamCandidate` will contain no inference variables,
+ /// since it was usually produced directly from a `DefId`. However,
+ /// certain cases (currently only librustdoc's blanket impl finder),
+ /// a `ParamEnv` may be explicitly constructed with inference types.
+ /// When this is the case, we do *not* want to cache the resulting selection
+ /// candidate. This is due to the fact that it might not always be possible
+ /// to equate the obligation's trait ref and the candidate's trait ref,
+ /// if more constraints end up getting added to an inference variable.
+ ///
+ /// Because of this, we always want to re-run the full selection
+ /// process for our obligation the next time we see it, since
+ /// we might end up picking a different `SelectionCandidate` (or none at all).
+ fn can_cache_candidate(
+ &self,
+ result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
+ ) -> bool {
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return false;
+ }
+ match result {
+ Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(),
+ _ => true,
+ }
+ }
+
+ #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")]
+ fn insert_candidate_cache(
+ &mut self,
+ mut param_env: ty::ParamEnv<'tcx>,
+ cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ dep_node: DepNodeIndex,
+ candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
+ ) {
+ let tcx = self.tcx();
+ let mut pred = cache_fresh_trait_pred.skip_binder();
+
+ pred.remap_constness(&mut param_env);
+
+ if !self.can_cache_candidate(&candidate) {
+ debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable");
+ return;
+ }
+
+ if self.can_use_global_caches(param_env) {
+ if let Err(Overflow(OverflowError::Canonical)) = candidate {
+ // Don't cache overflow globally; we only produce this in certain modes.
+ } else if !pred.needs_infer() {
+ if !candidate.needs_infer() {
+ debug!(?pred, ?candidate, "insert_candidate_cache global");
+ // This may overwrite the cache with the same value.
+ tcx.selection_cache.insert((param_env, pred), dep_node, candidate);
+ return;
+ }
+ }
+ }
+
+ debug!(?pred, ?candidate, "insert_candidate_cache local");
+ self.infcx.selection_cache.insert((param_env, pred), dep_node, candidate);
+ }
+
+ /// Matches a predicate against the bounds of its self type.
+ ///
+ /// Given an obligation like `<T as Foo>::Bar: Baz` where the self type is
+ /// a projection, look at the bounds of `T::Bar`, see if we can find a
+ /// `Baz` bound. We return indexes into the list returned by
+ /// `tcx.item_bounds` for any applicable bounds.
+ #[instrument(level = "debug", skip(self))]
+ fn match_projection_obligation_against_definition_bounds(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> smallvec::SmallVec<[usize; 2]> {
+ let poly_trait_predicate = self.infcx().resolve_vars_if_possible(obligation.predicate);
+ let placeholder_trait_predicate =
+ self.infcx().replace_bound_vars_with_placeholders(poly_trait_predicate);
+ debug!(?placeholder_trait_predicate);
+
+ let tcx = self.infcx.tcx;
+ let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
+ ty::Projection(ref data) => (data.item_def_id, data.substs),
+ ty::Opaque(def_id, substs) => (def_id, substs),
+ _ => {
+ span_bug!(
+ obligation.cause.span,
+ "match_projection_obligation_against_definition_bounds() called \
+ but self-ty is not a projection: {:?}",
+ placeholder_trait_predicate.trait_ref.self_ty()
+ );
+ }
+ };
+ let bounds = tcx.bound_item_bounds(def_id).subst(tcx, substs);
+
+ // The bounds returned by `item_bounds` may contain duplicates after
+ // normalization, so try to deduplicate when possible to avoid
+ // unnecessary ambiguity.
+ let mut distinct_normalized_bounds = FxHashSet::default();
+
+ let matching_bounds = bounds
+ .iter()
+ .enumerate()
+ .filter_map(|(idx, bound)| {
+ let bound_predicate = bound.kind();
+ if let ty::PredicateKind::Trait(pred) = bound_predicate.skip_binder() {
+ let bound = bound_predicate.rebind(pred.trait_ref);
+ if self.infcx.probe(|_| {
+ match self.match_normalize_trait_ref(
+ obligation,
+ bound,
+ placeholder_trait_predicate.trait_ref,
+ ) {
+ Ok(None) => true,
+ Ok(Some(normalized_trait))
+ if distinct_normalized_bounds.insert(normalized_trait) =>
+ {
+ true
+ }
+ _ => false,
+ }
+ }) {
+ return Some(idx);
+ }
+ }
+ None
+ })
+ .collect();
+
+ debug!(?matching_bounds);
+ matching_bounds
+ }
+
+ /// Equates the trait in `obligation` with trait bound. If the two traits
+ /// can be equated and the normalized trait bound doesn't contain inference
+ /// variables or placeholders, the normalized bound is returned.
+ fn match_normalize_trait_ref(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ trait_bound: ty::PolyTraitRef<'tcx>,
+ placeholder_trait_ref: ty::TraitRef<'tcx>,
+ ) -> Result<Option<ty::PolyTraitRef<'tcx>>, ()> {
+ debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars());
+ if placeholder_trait_ref.def_id != trait_bound.def_id() {
+ // Avoid unnecessary normalization
+ return Err(());
+ }
+
+ let Normalized { value: trait_bound, obligations: _ } = ensure_sufficient_stack(|| {
+ project::normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ trait_bound,
+ )
+ });
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .define_opaque_types(false)
+ .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound)
+ .map(|InferOk { obligations: _, value: () }| {
+ // This method is called within a probe, so we can't have
+ // inference variables and placeholders escape.
+ if !trait_bound.needs_infer() && !trait_bound.has_placeholders() {
+ Some(trait_bound)
+ } else {
+ None
+ }
+ })
+ .map_err(|_| ())
+ }
+
+ fn where_clause_may_apply<'o>(
+ &mut self,
+ stack: &TraitObligationStack<'o, 'tcx>,
+ where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<EvaluationResult, OverflowError> {
+ self.evaluation_probe(|this| {
+ match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
+ Ok(obligations) => this.evaluate_predicates_recursively(stack.list(), obligations),
+ Err(()) => Ok(EvaluatedToErr),
+ }
+ })
+ }
+
+ /// Return `Yes` if the obligation's predicate type applies to the env_predicate, and
+ /// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT,
+ /// and applying this env_predicate constrains any of the obligation's GAT substitutions.
+ ///
+ /// This behavior is a somewhat of a hack to prevent over-constraining inference variables
+ /// in cases like #91762.
+ pub(super) fn match_projection_projections(
+ &mut self,
+ obligation: &ProjectionTyObligation<'tcx>,
+ env_predicate: PolyProjectionPredicate<'tcx>,
+ potentially_unnormalized_candidates: bool,
+ ) -> ProjectionMatchesProjection {
+ let mut nested_obligations = Vec::new();
+ let infer_predicate = self.infcx.replace_bound_vars_with_fresh_vars(
+ obligation.cause.span,
+ LateBoundRegionConversionTime::HigherRankedType,
+ env_predicate,
+ );
+ let infer_projection = if potentially_unnormalized_candidates {
+ ensure_sufficient_stack(|| {
+ project::normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ infer_predicate.projection_ty,
+ &mut nested_obligations,
+ )
+ })
+ } else {
+ infer_predicate.projection_ty
+ };
+
+ let is_match = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .define_opaque_types(false)
+ .sup(obligation.predicate, infer_projection)
+ .map_or(false, |InferOk { obligations, value: () }| {
+ self.evaluate_predicates_recursively(
+ TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
+ nested_obligations.into_iter().chain(obligations),
+ )
+ .map_or(false, |res| res.may_apply())
+ });
+
+ if is_match {
+ let generics = self.tcx().generics_of(obligation.predicate.item_def_id);
+ // FIXME(generic-associated-types): Addresses aggressive inference in #92917.
+ // If this type is a GAT, and of the GAT substs resolve to something new,
+ // that means that we must have newly inferred something about the GAT.
+ // We should give up in that case.
+ if !generics.params.is_empty()
+ && obligation.predicate.substs[generics.parent_count..]
+ .iter()
+ .any(|&p| p.has_infer_types_or_consts() && self.infcx.shallow_resolve(p) != p)
+ {
+ ProjectionMatchesProjection::Ambiguous
+ } else {
+ ProjectionMatchesProjection::Yes
+ }
+ } else {
+ ProjectionMatchesProjection::No
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // WINNOW
+ //
+ // Winnowing is the process of attempting to resolve ambiguity by
+ // probing further. During the winnowing process, we unify all
+ // type variables and then we also attempt to evaluate recursive
+ // bounds to see if they are satisfied.
+
+ /// Returns `true` if `victim` should be dropped in favor of
+ /// `other`. Generally speaking we will drop duplicate
+ /// candidates and prefer where-clause candidates.
+ ///
+ /// See the comment for "SelectionCandidate" for more details.
+ fn candidate_should_be_dropped_in_favor_of(
+ &mut self,
+ victim: &EvaluatedCandidate<'tcx>,
+ other: &EvaluatedCandidate<'tcx>,
+ needs_infer: bool,
+ ) -> bool {
+ if victim.candidate == other.candidate {
+ return true;
+ }
+
+ // Check if a bound would previously have been removed when normalizing
+ // the param_env so that it can be given the lowest priority. See
+ // #50825 for the motivation for this.
+ let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
+ cand.is_global() && !cand.has_late_bound_regions()
+ };
+
+ // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
+ // `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else.
+ //
+ // This is a fix for #53123 and prevents winnowing from accidentally extending the
+ // lifetime of a variable.
+ match (&other.candidate, &victim.candidate) {
+ (_, AutoImplCandidate(..)) | (AutoImplCandidate(..), _) => {
+ bug!(
+ "default implementations shouldn't be recorded \
+ when there are other valid candidates"
+ );
+ }
+
+ // FIXME(@jswrenn): this should probably be more sophisticated
+ (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
+
+ // (*)
+ (
+ BuiltinCandidate { has_nested: false }
+ | DiscriminantKindCandidate
+ | PointeeCandidate
+ | ConstDestructCandidate(_),
+ _,
+ ) => true,
+ (
+ _,
+ BuiltinCandidate { has_nested: false }
+ | DiscriminantKindCandidate
+ | PointeeCandidate
+ | ConstDestructCandidate(_),
+ ) => false,
+
+ (ParamCandidate(other), ParamCandidate(victim)) => {
+ let same_except_bound_vars = other.skip_binder().trait_ref
+ == victim.skip_binder().trait_ref
+ && other.skip_binder().constness == victim.skip_binder().constness
+ && other.skip_binder().polarity == victim.skip_binder().polarity
+ && !other.skip_binder().trait_ref.has_escaping_bound_vars();
+ if same_except_bound_vars {
+ // See issue #84398. In short, we can generate multiple ParamCandidates which are
+ // the same except for unused bound vars. Just pick the one with the fewest bound vars
+ // or the current one if tied (they should both evaluate to the same answer). This is
+ // probably best characterized as a "hack", since we might prefer to just do our
+ // best to *not* create essentially duplicate candidates in the first place.
+ other.bound_vars().len() <= victim.bound_vars().len()
+ } else if other.skip_binder().trait_ref == victim.skip_binder().trait_ref
+ && victim.skip_binder().constness == ty::BoundConstness::NotConst
+ && other.skip_binder().polarity == victim.skip_binder().polarity
+ {
+ // Drop otherwise equivalent non-const candidates in favor of const candidates.
+ true
+ } else {
+ false
+ }
+ }
+
+ // Drop otherwise equivalent non-const fn pointer candidates
+ (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
+
+ // Global bounds from the where clause should be ignored
+ // here (see issue #50825). Otherwise, we have a where
+ // clause so don't go around looking for impls.
+ // Arbitrarily give param candidates priority
+ // over projection and object candidates.
+ (
+ ParamCandidate(ref cand),
+ ImplCandidate(..)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate { .. }
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
+ | BuiltinCandidate { .. }
+ | TraitAliasCandidate(..)
+ | ObjectCandidate(_)
+ | ProjectionCandidate(_),
+ ) => !is_global(cand),
+ (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+ // Prefer these to a global where-clause bound
+ // (see issue #50825).
+ is_global(cand)
+ }
+ (
+ ImplCandidate(_)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate { .. }
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
+ | BuiltinCandidate { has_nested: true }
+ | TraitAliasCandidate(..),
+ ParamCandidate(ref cand),
+ ) => {
+ // Prefer these to a global where-clause bound
+ // (see issue #50825).
+ is_global(cand) && other.evaluation.must_apply_modulo_regions()
+ }
+
+ (ProjectionCandidate(i), ProjectionCandidate(j))
+ | (ObjectCandidate(i), ObjectCandidate(j)) => {
+ // Arbitrarily pick the lower numbered candidate for backwards
+ // compatibility reasons. Don't let this affect inference.
+ i < j && !needs_infer
+ }
+ (ObjectCandidate(_), ProjectionCandidate(_))
+ | (ProjectionCandidate(_), ObjectCandidate(_)) => {
+ bug!("Have both object and projection candidate")
+ }
+
+ // Arbitrarily give projection and object candidates priority.
+ (
+ ObjectCandidate(_) | ProjectionCandidate(_),
+ ImplCandidate(..)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate { .. }
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
+ | BuiltinCandidate { .. }
+ | TraitAliasCandidate(..),
+ ) => true,
+
+ (
+ ImplCandidate(..)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate { .. }
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
+ | BuiltinCandidate { .. }
+ | TraitAliasCandidate(..),
+ ObjectCandidate(_) | ProjectionCandidate(_),
+ ) => false,
+
+ (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => {
+ // See if we can toss out `victim` based on specialization.
+ // This requires us to know *for sure* that the `other` impl applies
+ // i.e., `EvaluatedToOk`.
+ //
+ // FIXME(@lcnr): Using `modulo_regions` here seems kind of scary
+ // to me but is required for `std` to compile, so I didn't change it
+ // for now.
+ let tcx = self.tcx();
+ if other.evaluation.must_apply_modulo_regions() {
+ if tcx.specializes((other_def, victim_def)) {
+ return true;
+ }
+ }
+
+ if other.evaluation.must_apply_considering_regions() {
+ match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+ Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
+ // Subtle: If the predicate we are evaluating has inference
+ // variables, do *not* allow discarding candidates due to
+ // marker trait impls.
+ //
+ // Without this restriction, we could end up accidentally
+ // constraining inference variables based on an arbitrarily
+ // chosen trait impl.
+ //
+ // Imagine we have the following code:
+ //
+ // ```rust
+ // #[marker] trait MyTrait {}
+ // impl MyTrait for u8 {}
+ // impl MyTrait for bool {}
+ // ```
+ //
+ // And we are evaluating the predicate `<_#0t as MyTrait>`.
+ //
+ // During selection, we will end up with one candidate for each
+ // impl of `MyTrait`. If we were to discard one impl in favor
+ // of the other, we would be left with one candidate, causing
+ // us to "successfully" select the predicate, unifying
+ // _#0t with (for example) `u8`.
+ //
+ // However, we have no reason to believe that this unification
+ // is correct - we've essentially just picked an arbitrary
+ // *possibility* for _#0t, and required that this be the *only*
+ // possibility.
+ //
+ // Eventually, we will either:
+ // 1) Unify all inference variables in the predicate through
+ // some other means (e.g. type-checking of a function). We will
+ // then be in a position to drop marker trait candidates
+ // without constraining inference variables (since there are
+ // none left to constrain)
+ // 2) Be left with some unconstrained inference variables. We
+ // will then correctly report an inference error, since the
+ // existence of multiple marker trait impls tells us nothing
+ // about which one should actually apply.
+ !needs_infer
+ }
+ Some(_) => true,
+ None => false,
+ }
+ } else {
+ false
+ }
+ }
+
+ // Everything else is ambiguous
+ (
+ ImplCandidate(_)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate { .. }
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
+ | BuiltinCandidate { has_nested: true }
+ | TraitAliasCandidate(..),
+ ImplCandidate(_)
+ | ClosureCandidate
+ | GeneratorCandidate
+ | FnPointerCandidate { .. }
+ | BuiltinObjectCandidate
+ | BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
+ | BuiltinCandidate { has_nested: true }
+ | TraitAliasCandidate(..),
+ ) => false,
+ }
+ }
+
+ fn sized_conditions(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> BuiltinImplConditions<'tcx> {
+ use self::BuiltinImplConditions::{Ambiguous, None, Where};
+
+ // NOTE: binder moved to (*)
+ let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
+
+ match self_ty.kind() {
+ ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+ | ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::RawPtr(..)
+ | ty::Char
+ | ty::Ref(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Array(..)
+ | ty::Closure(..)
+ | ty::Never
+ | ty::Error(_) => {
+ // safe for everything
+ Where(ty::Binder::dummy(Vec::new()))
+ }
+
+ ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
+
+ ty::Tuple(tys) => Where(
+ obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
+ ),
+
+ ty::Adt(def, substs) => {
+ let sized_crit = def.sized_constraint(self.tcx());
+ // (*) binder moved here
+ Where(obligation.predicate.rebind({
+ sized_crit
+ .0
+ .iter()
+ .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs))
+ .collect()
+ }))
+ }
+
+ ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None,
+ ty::Infer(ty::TyVar(_)) => Ambiguous,
+
+ ty::Placeholder(..)
+ | ty::Bound(..)
+ | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+ }
+ }
+ }
+
+ fn copy_clone_conditions(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> BuiltinImplConditions<'tcx> {
+ // NOTE: binder moved to (*)
+ let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
+
+ use self::BuiltinImplConditions::{Ambiguous, None, Where};
+
+ match *self_ty.kind() {
+ ty::Infer(ty::IntVar(_))
+ | ty::Infer(ty::FloatVar(_))
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())),
+
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::Char
+ | ty::RawPtr(..)
+ | ty::Never
+ | ty::Ref(_, _, hir::Mutability::Not)
+ | ty::Array(..) => {
+ // Implementations provided in libcore
+ None
+ }
+
+ ty::Dynamic(..)
+ | ty::Str
+ | ty::Slice(..)
+ | ty::Generator(..)
+ | ty::GeneratorWitness(..)
+ | ty::Foreign(..)
+ | ty::Ref(_, _, hir::Mutability::Mut) => None,
+
+ ty::Tuple(tys) => {
+ // (*) binder moved here
+ Where(obligation.predicate.rebind(tys.iter().collect()))
+ }
+
+ ty::Closure(_, substs) => {
+ // (*) binder moved here
+ let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+ if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+ // Not yet resolved.
+ Ambiguous
+ } else {
+ Where(obligation.predicate.rebind(substs.as_closure().upvar_tys().collect()))
+ }
+ }
+
+ ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
+ // Fallback to whatever user-defined impls exist in this case.
+ None
+ }
+
+ ty::Infer(ty::TyVar(_)) => {
+ // Unbound type variable. Might or might not have
+ // applicable impls and so forth, depending on what
+ // those type variables wind up being bound to.
+ Ambiguous
+ }
+
+ ty::Placeholder(..)
+ | ty::Bound(..)
+ | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
+ }
+ }
+ }
+
+ /// For default impls, we need to break apart a type into its
+ /// "constituent types" -- meaning, the types that it contains.
+ ///
+ /// Here are some (simple) examples:
+ ///
+ /// ```ignore (illustrative)
+ /// (i32, u32) -> [i32, u32]
+ /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32]
+ /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
+ /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
+ /// ```
+ fn constituent_types_for_ty(
+ &self,
+ t: ty::Binder<'tcx, Ty<'tcx>>,
+ ) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> {
+ match *t.skip_binder().kind() {
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Float(_)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::Str
+ | ty::Error(_)
+ | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+ | ty::Never
+ | ty::Char => ty::Binder::dummy(Vec::new()),
+
+ ty::Placeholder(..)
+ | ty::Dynamic(..)
+ | ty::Param(..)
+ | ty::Foreign(..)
+ | ty::Projection(..)
+ | ty::Bound(..)
+ | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("asked to assemble constituent types of unexpected type: {:?}", t);
+ }
+
+ ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
+ t.rebind(vec![element_ty])
+ }
+
+ ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
+
+ ty::Tuple(ref tys) => {
+ // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
+ t.rebind(tys.iter().collect())
+ }
+
+ ty::Closure(_, ref substs) => {
+ let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+ t.rebind(vec![ty])
+ }
+
+ ty::Generator(_, ref substs, _) => {
+ let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
+ let witness = substs.as_generator().witness();
+ t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
+ }
+
+ ty::GeneratorWitness(types) => {
+ debug_assert!(!types.has_escaping_bound_vars());
+ types.map_bound(|types| types.to_vec())
+ }
+
+ // For `PhantomData<T>`, we pass `T`.
+ ty::Adt(def, substs) if def.is_phantom_data() => t.rebind(substs.types().collect()),
+
+ ty::Adt(def, substs) => {
+ t.rebind(def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect())
+ }
+
+ ty::Opaque(def_id, substs) => {
+ // We can resolve the `impl Trait` to its concrete type,
+ // which enforces a DAG between the functions requiring
+ // the auto trait bounds in question.
+ t.rebind(vec![self.tcx().bound_type_of(def_id).subst(self.tcx(), substs)])
+ }
+ }
+ }
+
+ fn collect_predicates_for_types(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ recursion_depth: usize,
+ trait_def_id: DefId,
+ types: ty::Binder<'tcx, Vec<Ty<'tcx>>>,
+ ) -> Vec<PredicateObligation<'tcx>> {
+ // Because the types were potentially derived from
+ // higher-ranked obligations they may reference late-bound
+ // regions. For example, `for<'a> Foo<&'a i32> : Copy` would
+ // yield a type like `for<'a> &'a i32`. In general, we
+ // maintain the invariant that we never manipulate bound
+ // regions, so we have to process these bound regions somehow.
+ //
+ // The strategy is to:
+ //
+ // 1. Instantiate those regions to placeholder regions (e.g.,
+ // `for<'a> &'a i32` becomes `&0 i32`.
+ // 2. Produce something like `&'0 i32 : Copy`
+ // 3. Re-bind the regions back to `for<'a> &'a i32 : Copy`
+
+ types
+ .as_ref()
+ .skip_binder() // binder moved -\
+ .iter()
+ .flat_map(|ty| {
+ let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
+
+ let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
+ let Normalized { value: normalized_ty, mut obligations } =
+ ensure_sufficient_stack(|| {
+ project::normalize_with_depth(
+ self,
+ param_env,
+ cause.clone(),
+ recursion_depth,
+ placeholder_ty,
+ )
+ });
+ let placeholder_obligation = predicate_for_trait_def(
+ self.tcx(),
+ param_env,
+ cause.clone(),
+ trait_def_id,
+ recursion_depth,
+ normalized_ty,
+ &[],
+ );
+ obligations.push(placeholder_obligation);
+ obligations
+ })
+ .collect()
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Matching
+ //
+ // Matching is a common path used for both evaluation and
+ // confirmation. It basically unifies types that appear in impls
+ // and traits. This does affect the surrounding environment;
+ // therefore, when used during evaluation, match routines must be
+ // run inside of a `probe()` so that their side-effects are
+ // contained.
+
+ fn rematch_impl(
+ &mut self,
+ impl_def_id: DefId,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Normalized<'tcx, SubstsRef<'tcx>> {
+ let impl_trait_ref = self.tcx().bound_impl_trait_ref(impl_def_id).unwrap();
+ match self.match_impl(impl_def_id, impl_trait_ref, obligation) {
+ Ok(substs) => substs,
+ Err(()) => {
+ self.infcx.tcx.sess.delay_span_bug(
+ obligation.cause.span,
+ &format!(
+ "Impl {:?} was matchable against {:?} but now is not",
+ impl_def_id, obligation
+ ),
+ );
+ let value = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
+ let err = self.tcx().ty_error();
+ let value = value.fold_with(&mut BottomUpFolder {
+ tcx: self.tcx(),
+ ty_op: |_| err,
+ lt_op: |l| l,
+ ct_op: |c| c,
+ });
+ Normalized { value, obligations: vec![] }
+ }
+ }
+ }
+
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn match_impl(
+ &mut self,
+ impl_def_id: DefId,
+ impl_trait_ref: EarlyBinder<ty::TraitRef<'tcx>>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
+ let placeholder_obligation =
+ self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
+ let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref;
+
+ let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id);
+
+ let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs);
+
+ debug!(?impl_trait_ref);
+
+ let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } =
+ ensure_sufficient_stack(|| {
+ project::normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ impl_trait_ref,
+ )
+ });
+
+ debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref);
+
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObligationCauseCode::MatchImpl(obligation.cause.clone(), impl_def_id),
+ );
+
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&cause, obligation.param_env)
+ .define_opaque_types(false)
+ .eq(placeholder_obligation_trait_ref, impl_trait_ref)
+ .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?;
+ nested_obligations.extend(obligations);
+
+ if !self.intercrate
+ && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation
+ {
+ debug!("match_impl: reservation impls only apply in intercrate mode");
+ return Err(());
+ }
+
+ debug!(?impl_substs, ?nested_obligations, "match_impl: success");
+ Ok(Normalized { value: impl_substs, obligations: nested_obligations })
+ }
+
+ fn fast_reject_trait_refs(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ impl_trait_ref: &ty::TraitRef<'tcx>,
+ ) -> bool {
+ // We can avoid creating type variables and doing the full
+ // substitution if we find that any of the input types, when
+ // simplified, do not match.
+ let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsPlaceholder };
+ iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs)
+ .any(|(obl, imp)| !drcx.generic_args_may_unify(obl, imp))
+ }
+
+ /// Normalize `where_clause_trait_ref` and try to match it against
+ /// `obligation`. If successful, return any predicates that
+ /// result from the normalization.
+ fn match_where_clause_trait_ref(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ where_clause_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+ self.match_poly_trait_ref(obligation, where_clause_trait_ref)
+ }
+
+ /// Returns `Ok` if `poly_trait_ref` being true implies that the
+ /// obligation is satisfied.
+ #[instrument(skip(self), level = "debug")]
+ fn match_poly_trait_ref(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ poly_trait_ref: ty::PolyTraitRef<'tcx>,
+ ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ // We don't want predicates for opaque types to just match all other types,
+ // if there is an obligation on the opaque type, then that obligation must be met
+ // opaquely. Otherwise we'd match any obligation to the opaque type and then error
+ // out later.
+ .define_opaque_types(false)
+ .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
+ .map(|InferOk { obligations, .. }| obligations)
+ .map_err(|_| ())
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Miscellany
+
+ fn match_fresh_trait_refs(
+ &self,
+ previous: ty::PolyTraitPredicate<'tcx>,
+ current: ty::PolyTraitPredicate<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> bool {
+ let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
+ matcher.relate(previous, current).is_ok()
+ }
+
+ fn push_stack<'o>(
+ &mut self,
+ previous_stack: TraitObligationStackList<'o, 'tcx>,
+ obligation: &'o TraitObligation<'tcx>,
+ ) -> TraitObligationStack<'o, 'tcx> {
+ let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener);
+
+ let dfn = previous_stack.cache.next_dfn();
+ let depth = previous_stack.depth() + 1;
+ TraitObligationStack {
+ obligation,
+ fresh_trait_pred,
+ reached_depth: Cell::new(depth),
+ previous: previous_stack,
+ dfn,
+ depth,
+ }
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn closure_trait_ref_unnormalized(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ substs: SubstsRef<'tcx>,
+ ) -> ty::PolyTraitRef<'tcx> {
+ let closure_sig = substs.as_closure().sig();
+
+ debug!(?closure_sig);
+
+ // (1) Feels icky to skip the binder here, but OTOH we know
+ // that the self-type is an unboxed closure type and hence is
+ // in fact unparameterized (or at least does not reference any
+ // regions bound in the obligation). Still probably some
+ // refactoring could make this nicer.
+ closure_trait_ref_and_return_type(
+ self.tcx(),
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().self_ty(), // (1)
+ closure_sig,
+ util::TupleArgumentsFlag::No,
+ )
+ .map_bound(|(trait_ref, _)| trait_ref)
+ }
+
+ fn generator_trait_ref_unnormalized(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ substs: SubstsRef<'tcx>,
+ ) -> ty::PolyTraitRef<'tcx> {
+ let gen_sig = substs.as_generator().poly_sig();
+
+ // (1) Feels icky to skip the binder here, but OTOH we know
+ // that the self-type is an generator type and hence is
+ // in fact unparameterized (or at least does not reference any
+ // regions bound in the obligation). Still probably some
+ // refactoring could make this nicer.
+
+ super::util::generator_trait_ref_and_outputs(
+ self.tcx(),
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().self_ty(), // (1)
+ gen_sig,
+ )
+ .map_bound(|(trait_ref, ..)| trait_ref)
+ }
+
+ /// Returns the obligations that are implied by instantiating an
+ /// impl or trait. The obligations are substituted and fully
+ /// normalized. This is used when confirming an impl or default
+ /// impl.
+ #[tracing::instrument(level = "debug", skip(self, cause, param_env))]
+ fn impl_or_trait_obligations(
+ &mut self,
+ cause: &ObligationCause<'tcx>,
+ recursion_depth: usize,
+ param_env: ty::ParamEnv<'tcx>,
+ def_id: DefId, // of impl or trait
+ substs: SubstsRef<'tcx>, // for impl or trait
+ parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ ) -> Vec<PredicateObligation<'tcx>> {
+ let tcx = self.tcx();
+
+ // To allow for one-pass evaluation of the nested obligation,
+ // each predicate must be preceded by the obligations required
+ // to normalize it.
+ // for example, if we have:
+ // impl<U: Iterator<Item: Copy>, V: Iterator<Item = U>> Foo for V
+ // the impl will have the following predicates:
+ // <V as Iterator>::Item = U,
+ // U: Iterator, U: Sized,
+ // V: Iterator, V: Sized,
+ // <U as Iterator>::Item: Copy
+ // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last
+ // obligation will normalize to `<$0 as Iterator>::Item = $1` and
+ // `$1: Copy`, so we must ensure the obligations are emitted in
+ // that order.
+ let predicates = tcx.bound_predicates_of(def_id);
+ debug!(?predicates);
+ assert_eq!(predicates.0.parent, None);
+ let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
+ for (predicate, span) in predicates.0.predicates {
+ let span = *span;
+ let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
+ ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+ derived,
+ impl_def_id: def_id,
+ span,
+ }))
+ });
+ let predicate = normalize_with_depth_to(
+ self,
+ param_env,
+ cause.clone(),
+ recursion_depth,
+ predicates.rebind(*predicate).subst(tcx, substs),
+ &mut obligations,
+ );
+ obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
+ }
+
+ obligations
+ }
+}
+
+impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
+ fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
+ TraitObligationStackList::with(self)
+ }
+
+ fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> {
+ self.previous.cache
+ }
+
+ fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> {
+ self.list()
+ }
+
+ /// Indicates that attempting to evaluate this stack entry
+ /// required accessing something from the stack at depth `reached_depth`.
+ fn update_reached_depth(&self, reached_depth: usize) {
+ assert!(
+ self.depth >= reached_depth,
+ "invoked `update_reached_depth` with something under this stack: \
+ self.depth={} reached_depth={}",
+ self.depth,
+ reached_depth,
+ );
+ debug!(reached_depth, "update_reached_depth");
+ let mut p = self;
+ while reached_depth < p.depth {
+ debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant");
+ p.reached_depth.set(p.reached_depth.get().min(reached_depth));
+ p = p.previous.head.unwrap();
+ }
+ }
+}
+
+/// The "provisional evaluation cache" is used to store intermediate cache results
+/// when solving auto traits. Auto traits are unusual in that they can support
+/// cycles. So, for example, a "proof tree" like this would be ok:
+///
+/// - `Foo<T>: Send` :-
+/// - `Bar<T>: Send` :-
+/// - `Foo<T>: Send` -- cycle, but ok
+/// - `Baz<T>: Send`
+///
+/// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and
+/// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`.
+/// For non-auto traits, this cycle would be an error, but for auto traits (because
+/// they are coinductive) it is considered ok.
+///
+/// However, there is a complication: at the point where we have
+/// "proven" `Bar<T>: Send`, we have in fact only proven it
+/// *provisionally*. In particular, we proved that `Bar<T>: Send`
+/// *under the assumption* that `Foo<T>: Send`. But what if we later
+/// find out this assumption is wrong? Specifically, we could
+/// encounter some kind of error proving `Baz<T>: Send`. In that case,
+/// `Bar<T>: Send` didn't turn out to be true.
+///
+/// In Issue #60010, we found a bug in rustc where it would cache
+/// these intermediate results. This was fixed in #60444 by disabling
+/// *all* caching for things involved in a cycle -- in our example,
+/// that would mean we don't cache that `Bar<T>: Send`. But this led
+/// to large slowdowns.
+///
+/// Specifically, imagine this scenario, where proving `Baz<T>: Send`
+/// first requires proving `Bar<T>: Send` (which is true:
+///
+/// - `Foo<T>: Send` :-
+/// - `Bar<T>: Send` :-
+/// - `Foo<T>: Send` -- cycle, but ok
+/// - `Baz<T>: Send`
+/// - `Bar<T>: Send` -- would be nice for this to be a cache hit!
+/// - `*const T: Send` -- but what if we later encounter an error?
+///
+/// The *provisional evaluation cache* resolves this issue. It stores
+/// cache results that we've proven but which were involved in a cycle
+/// in some way. We track the minimal stack depth (i.e., the
+/// farthest from the top of the stack) that we are dependent on.
+/// The idea is that the cache results within are all valid -- so long as
+/// none of the nodes in between the current node and the node at that minimum
+/// depth result in an error (in which case the cached results are just thrown away).
+///
+/// During evaluation, we consult this provisional cache and rely on
+/// it. Accessing a cached value is considered equivalent to accessing
+/// a result at `reached_depth`, so it marks the *current* solution as
+/// provisional as well. If an error is encountered, we toss out any
+/// provisional results added from the subtree that encountered the
+/// error. When we pop the node at `reached_depth` from the stack, we
+/// can commit all the things that remain in the provisional cache.
+struct ProvisionalEvaluationCache<'tcx> {
+ /// next "depth first number" to issue -- just a counter
+ dfn: Cell<usize>,
+
+ /// Map from cache key to the provisionally evaluated thing.
+ /// The cache entries contain the result but also the DFN in which they
+ /// were added. The DFN is used to clear out values on failure.
+ ///
+ /// Imagine we have a stack like:
+ ///
+ /// - `A B C` and we add a cache for the result of C (DFN 2)
+ /// - Then we have a stack `A B D` where `D` has DFN 3
+ /// - We try to solve D by evaluating E: `A B D E` (DFN 4)
+ /// - `E` generates various cache entries which have cyclic dependencies on `B`
+ /// - `A B D E F` and so forth
+ /// - the DFN of `F` for example would be 5
+ /// - then we determine that `E` is in error -- we will then clear
+ /// all cache values whose DFN is >= 4 -- in this case, that
+ /// means the cached value for `F`.
+ map: RefCell<FxHashMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
+
+ /// The stack of args that we assume to be true because a `WF(arg)` predicate
+ /// is on the stack above (and because of wellformedness is coinductive).
+ /// In an "ideal" world, this would share a stack with trait predicates in
+ /// `TraitObligationStack`. However, trait predicates are *much* hotter than
+ /// `WellFormed` predicates, and it's very likely that the additional matches
+ /// will have a perf effect. The value here is the well-formed `GenericArg`
+ /// and the depth of the trait predicate *above* that well-formed predicate.
+ wf_args: RefCell<Vec<(ty::GenericArg<'tcx>, usize)>>,
+}
+
+/// A cache value for the provisional cache: contains the depth-first
+/// number (DFN) and result.
+#[derive(Copy, Clone, Debug)]
+struct ProvisionalEvaluation {
+ from_dfn: usize,
+ reached_depth: usize,
+ result: EvaluationResult,
+}
+
+impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> {
+ fn default() -> Self {
+ Self { dfn: Cell::new(0), map: Default::default(), wf_args: Default::default() }
+ }
+}
+
+impl<'tcx> ProvisionalEvaluationCache<'tcx> {
+ /// Get the next DFN in sequence (basically a counter).
+ fn next_dfn(&self) -> usize {
+ let result = self.dfn.get();
+ self.dfn.set(result + 1);
+ result
+ }
+
+ /// Check the provisional cache for any result for
+ /// `fresh_trait_ref`. If there is a hit, then you must consider
+ /// it an access to the stack slots at depth
+ /// `reached_depth` (from the returned value).
+ fn get_provisional(
+ &self,
+ fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> Option<ProvisionalEvaluation> {
+ debug!(
+ ?fresh_trait_pred,
+ "get_provisional = {:#?}",
+ self.map.borrow().get(&fresh_trait_pred),
+ );
+ Some(*self.map.borrow().get(&fresh_trait_pred)?)
+ }
+
+ /// Insert a provisional result into the cache. The result came
+ /// from the node with the given DFN. It accessed a minimum depth
+ /// of `reached_depth` to compute. It evaluated `fresh_trait_pred`
+ /// and resulted in `result`.
+ fn insert_provisional(
+ &self,
+ from_dfn: usize,
+ reached_depth: usize,
+ fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
+ result: EvaluationResult,
+ ) {
+ debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
+
+ let mut map = self.map.borrow_mut();
+
+ // Subtle: when we complete working on the DFN `from_dfn`, anything
+ // that remains in the provisional cache must be dependent on some older
+ // stack entry than `from_dfn`. We have to update their depth with our transitive
+ // depth in that case or else it would be referring to some popped note.
+ //
+ // Example:
+ // A (reached depth 0)
+ // ...
+ // B // depth 1 -- reached depth = 0
+ // C // depth 2 -- reached depth = 1 (should be 0)
+ // B
+ // A // depth 0
+ // D (reached depth 1)
+ // C (cache -- reached depth = 2)
+ for (_k, v) in &mut *map {
+ if v.from_dfn >= from_dfn {
+ v.reached_depth = reached_depth.min(v.reached_depth);
+ }
+ }
+
+ map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
+ }
+
+ /// Invoked when the node with dfn `dfn` does not get a successful
+ /// result. This will clear out any provisional cache entries
+ /// that were added since `dfn` was created. This is because the
+ /// provisional entries are things which must assume that the
+ /// things on the stack at the time of their creation succeeded --
+ /// since the failing node is presently at the top of the stack,
+ /// these provisional entries must either depend on it or some
+ /// ancestor of it.
+ fn on_failure(&self, dfn: usize) {
+ debug!(?dfn, "on_failure");
+ self.map.borrow_mut().retain(|key, eval| {
+ if !eval.from_dfn >= dfn {
+ debug!("on_failure: removing {:?}", key);
+ false
+ } else {
+ true
+ }
+ });
+ }
+
+ /// Invoked when the node at depth `depth` completed without
+ /// depending on anything higher in the stack (if that completion
+ /// was a failure, then `on_failure` should have been invoked
+ /// already).
+ ///
+ /// Note that we may still have provisional cache items remaining
+ /// in the cache when this is done. For example, if there is a
+ /// cycle:
+ ///
+ /// * A depends on...
+ /// * B depends on A
+ /// * C depends on...
+ /// * D depends on C
+ /// * ...
+ ///
+ /// Then as we complete the C node we will have a provisional cache
+ /// with results for A, B, C, and D. This method would clear out
+ /// the C and D results, but leave A and B provisional.
+ ///
+ /// This is determined based on the DFN: we remove any provisional
+ /// results created since `dfn` started (e.g., in our example, dfn
+ /// would be 2, representing the C node, and hence we would
+ /// remove the result for D, which has DFN 3, but not the results for
+ /// A and B, which have DFNs 0 and 1 respectively).
+ ///
+ /// Note that we *do not* attempt to cache these cycle participants
+ /// in the evaluation cache. Doing so would require carefully computing
+ /// the correct `DepNode` to store in the cache entry:
+ /// cycle participants may implicitly depend on query results
+ /// related to other participants in the cycle, due to our logic
+ /// which examines the evaluation stack.
+ ///
+ /// We used to try to perform this caching,
+ /// but it lead to multiple incremental compilation ICEs
+ /// (see #92987 and #96319), and was very hard to understand.
+ /// Fortunately, removing the caching didn't seem to
+ /// have a performance impact in practice.
+ fn on_completion(&self, dfn: usize) {
+ debug!(?dfn, "on_completion");
+
+ for (fresh_trait_pred, eval) in
+ self.map.borrow_mut().drain_filter(|_k, eval| eval.from_dfn >= dfn)
+ {
+ debug!(?fresh_trait_pred, ?eval, "on_completion");
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+struct TraitObligationStackList<'o, 'tcx> {
+ cache: &'o ProvisionalEvaluationCache<'tcx>,
+ head: Option<&'o TraitObligationStack<'o, 'tcx>>,
+}
+
+impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> {
+ fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> {
+ TraitObligationStackList { cache, head: None }
+ }
+
+ fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> {
+ TraitObligationStackList { cache: r.cache(), head: Some(r) }
+ }
+
+ fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
+ self.head
+ }
+
+ fn depth(&self) -> usize {
+ if let Some(head) = self.head { head.depth } else { 0 }
+ }
+}
+
+impl<'o, 'tcx> Iterator for TraitObligationStackList<'o, 'tcx> {
+ type Item = &'o TraitObligationStack<'o, 'tcx>;
+
+ fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> {
+ let o = self.head?;
+ *self = o.previous;
+ Some(o)
+ }
+}
+
+impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "TraitObligationStack({:?})", self.obligation)
+ }
+}
+
+pub enum ProjectionMatchesProjection {
+ Yes,
+ Ambiguous,
+ No,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
new file mode 100644
index 000000000..6223c5ea3
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -0,0 +1,531 @@
+//! Logic and data structures related to impl specialization, explained in
+//! greater detail below.
+//!
+//! At the moment, this implementation support only the simple "chain" rule:
+//! If any two impls overlap, one must be a strict subset of the other.
+//!
+//! See the [rustc dev guide] for a bit more detail on how specialization
+//! fits together with the rest of the trait machinery.
+//!
+//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
+
+pub mod specialization_graph;
+use specialization_graph::GraphExt;
+
+use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use crate::traits::select::IntercrateAmbiguityCause;
+use crate::traits::{
+ self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt,
+};
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::{self, ImplSubject, TyCtxt};
+use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
+use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
+use rustc_span::{Span, DUMMY_SP};
+
+use super::SelectionContext;
+use super::{util, FulfillmentContext};
+
+/// Information pertinent to an overlapping impl error.
+#[derive(Debug)]
+pub struct OverlapError {
+ pub with_impl: DefId,
+ pub trait_desc: String,
+ pub self_desc: Option<String>,
+ pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
+ pub involves_placeholder: bool,
+}
+
+/// Given a subst for the requested impl, translate it to a subst
+/// appropriate for the actual item definition (whether it be in that impl,
+/// a parent impl, or the trait).
+///
+/// When we have selected one impl, but are actually using item definitions from
+/// a parent impl providing a default, we need a way to translate between the
+/// type parameters of the two impls. Here the `source_impl` is the one we've
+/// selected, and `source_substs` is a substitution of its generics.
+/// And `target_node` is the impl/trait we're actually going to get the
+/// definition from. The resulting substitution will map from `target_node`'s
+/// generics to `source_impl`'s generics as instantiated by `source_subst`.
+///
+/// For example, consider the following scenario:
+///
+/// ```ignore (illustrative)
+/// trait Foo { ... }
+/// impl<T, U> Foo for (T, U) { ... } // target impl
+/// impl<V> Foo for (V, V) { ... } // source impl
+/// ```
+///
+/// Suppose we have selected "source impl" with `V` instantiated with `u32`.
+/// This function will produce a substitution with `T` and `U` both mapping to `u32`.
+///
+/// where-clauses add some trickiness here, because they can be used to "define"
+/// an argument indirectly:
+///
+/// ```ignore (illustrative)
+/// impl<'a, I, T: 'a> Iterator for Cloned<I>
+/// where I: Iterator<Item = &'a T>, T: Clone
+/// ```
+///
+/// In a case like this, the substitution for `T` is determined indirectly,
+/// through associated type projection. We deal with such cases by using
+/// *fulfillment* to relate the two impls, requiring that all projections are
+/// resolved.
+pub fn translate_substs<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ source_impl: DefId,
+ source_substs: SubstsRef<'tcx>,
+ target_node: specialization_graph::Node,
+) -> SubstsRef<'tcx> {
+ debug!(
+ "translate_substs({:?}, {:?}, {:?}, {:?})",
+ param_env, source_impl, source_substs, target_node
+ );
+ let source_trait_ref =
+ infcx.tcx.bound_impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs);
+
+ // translate the Self and Param parts of the substitution, since those
+ // vary across impls
+ let target_substs = match target_node {
+ specialization_graph::Node::Impl(target_impl) => {
+ // no need to translate if we're targeting the impl we started with
+ if source_impl == target_impl {
+ return source_substs;
+ }
+
+ fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
+ |_| {
+ bug!(
+ "When translating substitutions for specialization, the expected \
+ specialization failed to hold"
+ )
+ },
+ )
+ }
+ specialization_graph::Node::Trait(..) => source_trait_ref.substs,
+ };
+
+ // directly inherent the method generics, since those do not vary across impls
+ source_substs.rebase_onto(infcx.tcx, source_impl, target_substs)
+}
+
+/// Is `impl1` a specialization of `impl2`?
+///
+/// Specialization is determined by the sets of types to which the impls apply;
+/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
+/// to.
+#[instrument(skip(tcx), level = "debug")]
+pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool {
+ // The feature gate should prevent introducing new specializations, but not
+ // taking advantage of upstream ones.
+ let features = tcx.features();
+ let specialization_enabled = features.specialization || features.min_specialization;
+ if !specialization_enabled && (impl1_def_id.is_local() || impl2_def_id.is_local()) {
+ return false;
+ }
+
+ // We determine whether there's a subset relationship by:
+ //
+ // - replacing bound vars with placeholders in impl1,
+ // - assuming the where clauses for impl1,
+ // - instantiating impl2 with fresh inference variables,
+ // - unifying,
+ // - attempting to prove the where clauses for impl2
+ //
+ // The last three steps are encapsulated in `fulfill_implication`.
+ //
+ // See RFC 1210 for more details and justification.
+
+ // Currently we do not allow e.g., a negative impl to specialize a positive one
+ if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) {
+ return false;
+ }
+
+ // create a parameter environment corresponding to a (placeholder) instantiation of impl1
+ let penv = tcx.param_env(impl1_def_id);
+ let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
+
+ // Create an infcx, taking the predicates of impl1 as assumptions:
+ tcx.infer_ctxt().enter(|infcx| {
+ let impl1_trait_ref = match traits::fully_normalize(
+ &infcx,
+ FulfillmentContext::new(),
+ ObligationCause::dummy(),
+ penv,
+ impl1_trait_ref,
+ ) {
+ Ok(impl1_trait_ref) => impl1_trait_ref,
+ Err(_errors) => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(impl1_def_id),
+ format!("failed to fully normalize {impl1_trait_ref}"),
+ );
+ impl1_trait_ref
+ }
+ };
+
+ // Attempt to prove that impl2 applies, given all of the above.
+ fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
+ })
+}
+
+/// Attempt to fulfill all obligations of `target_impl` after unification with
+/// `source_trait_ref`. If successful, returns a substitution for *all* the
+/// generics of `target_impl`, including both those needed to unify with
+/// `source_trait_ref` and those whose identity is determined via a where
+/// clause in the impl.
+fn fulfill_implication<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ source_trait_ref: ty::TraitRef<'tcx>,
+ target_impl: DefId,
+) -> Result<SubstsRef<'tcx>, ()> {
+ debug!(
+ "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
+ param_env, source_trait_ref, target_impl
+ );
+
+ let source_trait = ImplSubject::Trait(source_trait_ref);
+
+ let selcx = &mut SelectionContext::new(&infcx);
+ let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
+ let (target_trait, obligations) =
+ util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs);
+
+ // do the impls unify? If not, no specialization.
+ let Ok(InferOk { obligations: more_obligations, .. }) =
+ infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait, target_trait)
+ else {
+ debug!(
+ "fulfill_implication: {:?} does not unify with {:?}",
+ source_trait, target_trait
+ );
+ return Err(());
+ };
+
+ // attempt to prove all of the predicates for impl2 given those for impl1
+ // (which are packed up in penv)
+
+ infcx.save_and_restore_in_snapshot_flag(|infcx| {
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ for oblig in obligations.chain(more_obligations) {
+ fulfill_cx.register_predicate_obligation(&infcx, oblig);
+ }
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
+ debug!(
+ "fulfill_implication: an impl for {:?} specializes {:?}",
+ source_trait, target_trait
+ );
+
+ // Now resolve the *substitution* we built for the target earlier, replacing
+ // the inference variables inside with whatever we got from fulfillment.
+ Ok(infcx.resolve_vars_if_possible(target_substs))
+ }
+ errors => {
+ // no dice!
+ debug!(
+ "fulfill_implication: for impls on {:?} and {:?}, \
+ could not fulfill: {:?} given {:?}",
+ source_trait,
+ target_trait,
+ errors,
+ param_env.caller_bounds()
+ );
+ Err(())
+ }
+ }
+ })
+}
+
+// Query provider for `specialization_graph_of`.
+pub(super) fn specialization_graph_provider(
+ tcx: TyCtxt<'_>,
+ trait_id: DefId,
+) -> specialization_graph::Graph {
+ let mut sg = specialization_graph::Graph::new();
+ let overlap_mode = specialization_graph::OverlapMode::get(tcx, trait_id);
+
+ let mut trait_impls: Vec<_> = tcx.all_impls(trait_id).collect();
+
+ // The coherence checking implementation seems to rely on impls being
+ // iterated over (roughly) in definition order, so we are sorting by
+ // negated `CrateNum` (so remote definitions are visited first) and then
+ // by a flattened version of the `DefIndex`.
+ trait_impls
+ .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index()));
+
+ for impl_def_id in trait_impls {
+ if let Some(impl_def_id) = impl_def_id.as_local() {
+ // This is where impl overlap checking happens:
+ let insert_result = sg.insert(tcx, impl_def_id.to_def_id(), overlap_mode);
+ // Report error if there was one.
+ let (overlap, used_to_be_allowed) = match insert_result {
+ Err(overlap) => (Some(overlap), None),
+ Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)),
+ Ok(None) => (None, None),
+ };
+
+ if let Some(overlap) = overlap {
+ report_overlap_conflict(tcx, overlap, impl_def_id, used_to_be_allowed, &mut sg);
+ }
+ } else {
+ let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id);
+ sg.record_impl_from_cstore(tcx, parent, impl_def_id)
+ }
+ }
+
+ sg
+}
+
+// This function is only used when
+// encountering errors and inlining
+// it negatively impacts perf.
+#[cold]
+#[inline(never)]
+fn report_overlap_conflict(
+ tcx: TyCtxt<'_>,
+ overlap: OverlapError,
+ impl_def_id: LocalDefId,
+ used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
+ sg: &mut specialization_graph::Graph,
+) {
+ let impl_polarity = tcx.impl_polarity(impl_def_id.to_def_id());
+ let other_polarity = tcx.impl_polarity(overlap.with_impl);
+ match (impl_polarity, other_polarity) {
+ (ty::ImplPolarity::Negative, ty::ImplPolarity::Positive) => {
+ report_negative_positive_conflict(
+ tcx,
+ &overlap,
+ impl_def_id,
+ impl_def_id.to_def_id(),
+ overlap.with_impl,
+ sg,
+ );
+ }
+
+ (ty::ImplPolarity::Positive, ty::ImplPolarity::Negative) => {
+ report_negative_positive_conflict(
+ tcx,
+ &overlap,
+ impl_def_id,
+ overlap.with_impl,
+ impl_def_id.to_def_id(),
+ sg,
+ );
+ }
+
+ _ => {
+ report_conflicting_impls(tcx, overlap, impl_def_id, used_to_be_allowed, sg);
+ }
+ }
+}
+
+fn report_negative_positive_conflict(
+ tcx: TyCtxt<'_>,
+ overlap: &OverlapError,
+ local_impl_def_id: LocalDefId,
+ negative_impl_def_id: DefId,
+ positive_impl_def_id: DefId,
+ sg: &mut specialization_graph::Graph,
+) {
+ let impl_span = tcx.def_span(local_impl_def_id);
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_span,
+ E0751,
+ "found both positive and negative implementation of trait `{}`{}:",
+ overlap.trait_desc,
+ overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty))
+ );
+
+ match tcx.span_of_impl(negative_impl_def_id) {
+ Ok(span) => {
+ err.span_label(span, "negative implementation here");
+ }
+ Err(cname) => {
+ err.note(&format!("negative implementation in crate `{}`", cname));
+ }
+ }
+
+ match tcx.span_of_impl(positive_impl_def_id) {
+ Ok(span) => {
+ err.span_label(span, "positive implementation here");
+ }
+ Err(cname) => {
+ err.note(&format!("positive implementation in crate `{}`", cname));
+ }
+ }
+
+ sg.has_errored = Some(err.emit());
+}
+
+fn report_conflicting_impls(
+ tcx: TyCtxt<'_>,
+ overlap: OverlapError,
+ impl_def_id: LocalDefId,
+ used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
+ sg: &mut specialization_graph::Graph,
+) {
+ let impl_span = tcx.def_span(impl_def_id);
+
+ // Work to be done after we've built the DiagnosticBuilder. We have to define it
+ // now because the struct_lint methods don't return back the DiagnosticBuilder
+ // that's passed in.
+ fn decorate<G: EmissionGuarantee>(
+ tcx: TyCtxt<'_>,
+ overlap: OverlapError,
+ used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
+ impl_span: Span,
+ err: LintDiagnosticBuilder<'_, G>,
+ ) -> G {
+ let msg = format!(
+ "conflicting implementations of trait `{}`{}{}",
+ overlap.trait_desc,
+ overlap
+ .self_desc
+ .clone()
+ .map_or_else(String::new, |ty| { format!(" for type `{}`", ty) }),
+ match used_to_be_allowed {
+ Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
+ _ => "",
+ }
+ );
+ let mut err = err.build(&msg);
+ match tcx.span_of_impl(overlap.with_impl) {
+ Ok(span) => {
+ err.span_label(span, "first implementation here");
+
+ err.span_label(
+ impl_span,
+ format!(
+ "conflicting implementation{}",
+ overlap.self_desc.map_or_else(String::new, |ty| format!(" for `{}`", ty))
+ ),
+ );
+ }
+ Err(cname) => {
+ let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
+ Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
+ None => format!("conflicting implementation in crate `{}`", cname),
+ };
+ err.note(&msg);
+ }
+ }
+
+ for cause in &overlap.intercrate_ambiguity_causes {
+ cause.add_intercrate_ambiguity_hint(&mut err);
+ }
+
+ if overlap.involves_placeholder {
+ coherence::add_placeholder_note(&mut err);
+ }
+ err.emit()
+ }
+
+ match used_to_be_allowed {
+ None => {
+ let reported = if overlap.with_impl.is_local()
+ || tcx.orphan_check_impl(impl_def_id).is_ok()
+ {
+ let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
+ Some(decorate(
+ tcx,
+ overlap,
+ used_to_be_allowed,
+ impl_span,
+ LintDiagnosticBuilder::new(err),
+ ))
+ } else {
+ Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
+ };
+ sg.has_errored = reported;
+ }
+ Some(kind) => {
+ let lint = match kind {
+ FutureCompatOverlapErrorKind::Issue33140 => ORDER_DEPENDENT_TRAIT_OBJECTS,
+ FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK,
+ };
+ tcx.struct_span_lint_hir(
+ lint,
+ tcx.hir().local_def_id_to_hir_id(impl_def_id),
+ impl_span,
+ |ldb| {
+ decorate(tcx, overlap, used_to_be_allowed, impl_span, ldb);
+ },
+ );
+ }
+ };
+}
+
+/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
+/// string.
+pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+ use std::fmt::Write;
+
+ let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
+ let mut w = "impl".to_owned();
+
+ let substs = InternalSubsts::identity_for_item(tcx, impl_def_id);
+
+ // FIXME: Currently only handles ?Sized.
+ // Needs to support ?Move and ?DynSized when they are implemented.
+ let mut types_without_default_bounds = FxHashSet::default();
+ let sized_trait = tcx.lang_items().sized_trait();
+
+ if !substs.is_empty() {
+ types_without_default_bounds.extend(substs.types());
+ w.push('<');
+ w.push_str(
+ &substs
+ .iter()
+ .map(|k| k.to_string())
+ .filter(|k| k != "'_")
+ .collect::<Vec<_>>()
+ .join(", "),
+ );
+ w.push('>');
+ }
+
+ write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap();
+
+ // The predicates will contain default bounds like `T: Sized`. We need to
+ // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
+ let predicates = tcx.predicates_of(impl_def_id).predicates;
+ let mut pretty_predicates =
+ Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
+
+ for (mut p, _) in predicates {
+ if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
+ if Some(poly_trait_ref.def_id()) == sized_trait {
+ types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder());
+ continue;
+ }
+
+ if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness {
+ let new_trait_pred = poly_trait_ref.map_bound(|mut trait_pred| {
+ trait_pred.constness = ty::BoundConstness::NotConst;
+ trait_pred
+ });
+
+ p = tcx.mk_predicate(new_trait_pred.map_bound(ty::PredicateKind::Trait))
+ }
+ }
+ pretty_predicates.push(p.to_string());
+ }
+
+ pretty_predicates
+ .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty)));
+
+ if !pretty_predicates.is_empty() {
+ write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
+ }
+
+ w.push(';');
+ Some(w)
+}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
new file mode 100644
index 000000000..fcb73b43f
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -0,0 +1,395 @@
+use super::OverlapError;
+
+use crate::traits;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
+
+pub use rustc_middle::traits::specialization_graph::*;
+
+#[derive(Copy, Clone, Debug)]
+pub enum FutureCompatOverlapErrorKind {
+ Issue33140,
+ LeakCheck,
+}
+
+#[derive(Debug)]
+pub struct FutureCompatOverlapError {
+ pub error: OverlapError,
+ pub kind: FutureCompatOverlapErrorKind,
+}
+
+/// The result of attempting to insert an impl into a group of children.
+enum Inserted {
+ /// The impl was inserted as a new child in this group of children.
+ BecameNewSibling(Option<FutureCompatOverlapError>),
+
+ /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc.
+ ReplaceChildren(Vec<DefId>),
+
+ /// The impl is a specialization of an existing child.
+ ShouldRecurseOn(DefId),
+}
+
+trait ChildrenExt<'tcx> {
+ fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
+ fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId);
+
+ fn insert(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ impl_def_id: DefId,
+ simplified_self: Option<SimplifiedType>,
+ overlap_mode: OverlapMode,
+ ) -> Result<Inserted, OverlapError>;
+}
+
+impl ChildrenExt<'_> for Children {
+ /// Insert an impl into this set of children without comparing to any existing impls.
+ fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
+ {
+ debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
+ self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
+ } else {
+ debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id);
+ self.blanket_impls.push(impl_def_id)
+ }
+ }
+
+ /// Removes an impl from this set of children. Used when replacing
+ /// an impl with a parent. The impl must be present in the list of
+ /// children already.
+ fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let vec: &mut Vec<DefId>;
+ if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer)
+ {
+ debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
+ vec = self.non_blanket_impls.get_mut(&st).unwrap();
+ } else {
+ debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id);
+ vec = &mut self.blanket_impls;
+ }
+
+ let index = vec.iter().position(|d| *d == impl_def_id).unwrap();
+ vec.remove(index);
+ }
+
+ /// Attempt to insert an impl into this set of children, while comparing for
+ /// specialization relationships.
+ fn insert(
+ &mut self,
+ tcx: TyCtxt<'_>,
+ impl_def_id: DefId,
+ simplified_self: Option<SimplifiedType>,
+ overlap_mode: OverlapMode,
+ ) -> Result<Inserted, OverlapError> {
+ let mut last_lint = None;
+ let mut replace_children = Vec::new();
+
+ debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,);
+
+ let possible_siblings = match simplified_self {
+ Some(st) => PotentialSiblings::Filtered(filtered_children(self, st)),
+ None => PotentialSiblings::Unfiltered(iter_children(self)),
+ };
+
+ for possible_sibling in possible_siblings {
+ debug!(
+ "insert: impl_def_id={:?}, simplified_self={:?}, possible_sibling={:?}",
+ impl_def_id, simplified_self, possible_sibling,
+ );
+
+ let create_overlap_error = |overlap: traits::coherence::OverlapResult<'_>| {
+ let trait_ref = overlap.impl_header.trait_ref.unwrap();
+ let self_ty = trait_ref.self_ty();
+
+ // FIXME: should postpone string formatting until we decide to actually emit.
+ with_no_trimmed_paths!({
+ OverlapError {
+ with_impl: possible_sibling,
+ trait_desc: trait_ref.print_only_trait_path().to_string(),
+ // Only report the `Self` type if it has at least
+ // some outer concrete shell; otherwise, it's
+ // not adding much information.
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
+ involves_placeholder: overlap.involves_placeholder,
+ }
+ })
+ };
+
+ let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>,
+ last_lint: &mut _| {
+ // Found overlap, but no specialization; error out or report future-compat warning.
+
+ // Do we *still* get overlap if we disable the future-incompatible modes?
+ let should_err = traits::overlapping_impls(
+ tcx,
+ possible_sibling,
+ impl_def_id,
+ traits::SkipLeakCheck::default(),
+ overlap_mode,
+ |_| true,
+ || false,
+ );
+
+ let error = create_overlap_error(overlap);
+
+ if should_err {
+ Err(error)
+ } else {
+ *last_lint = Some(FutureCompatOverlapError {
+ error,
+ kind: FutureCompatOverlapErrorKind::LeakCheck,
+ });
+
+ Ok((false, false))
+ }
+ };
+
+ let last_lint_mut = &mut last_lint;
+ let (le, ge) = traits::overlapping_impls(
+ tcx,
+ possible_sibling,
+ impl_def_id,
+ traits::SkipLeakCheck::Yes,
+ overlap_mode,
+ |overlap| {
+ if let Some(overlap_kind) =
+ tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
+ {
+ match overlap_kind {
+ ty::ImplOverlapKind::Permitted { marker: _ } => {}
+ ty::ImplOverlapKind::Issue33140 => {
+ *last_lint_mut = Some(FutureCompatOverlapError {
+ error: create_overlap_error(overlap),
+ kind: FutureCompatOverlapErrorKind::Issue33140,
+ });
+ }
+ }
+
+ return Ok((false, false));
+ }
+
+ let le = tcx.specializes((impl_def_id, possible_sibling));
+ let ge = tcx.specializes((possible_sibling, impl_def_id));
+
+ if le == ge {
+ report_overlap_error(overlap, last_lint_mut)
+ } else {
+ Ok((le, ge))
+ }
+ },
+ || Ok((false, false)),
+ )?;
+
+ if le && !ge {
+ debug!(
+ "descending as child of TraitRef {:?}",
+ tcx.impl_trait_ref(possible_sibling).unwrap()
+ );
+
+ // The impl specializes `possible_sibling`.
+ return Ok(Inserted::ShouldRecurseOn(possible_sibling));
+ } else if ge && !le {
+ debug!(
+ "placing as parent of TraitRef {:?}",
+ tcx.impl_trait_ref(possible_sibling).unwrap()
+ );
+
+ replace_children.push(possible_sibling);
+ } else {
+ // Either there's no overlap, or the overlap was already reported by
+ // `overlap_error`.
+ }
+ }
+
+ if !replace_children.is_empty() {
+ return Ok(Inserted::ReplaceChildren(replace_children));
+ }
+
+ // No overlap with any potential siblings, so add as a new sibling.
+ debug!("placing as new sibling");
+ self.insert_blindly(tcx, impl_def_id);
+ Ok(Inserted::BecameNewSibling(last_lint))
+ }
+}
+
+fn iter_children(children: &mut Children) -> impl Iterator<Item = DefId> + '_ {
+ let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter());
+ children.blanket_impls.iter().chain(nonblanket).cloned()
+}
+
+fn filtered_children(
+ children: &mut Children,
+ st: SimplifiedType,
+) -> impl Iterator<Item = DefId> + '_ {
+ let nonblanket = children.non_blanket_impls.entry(st).or_default().iter();
+ children.blanket_impls.iter().chain(nonblanket).cloned()
+}
+
+// A custom iterator used by Children::insert
+enum PotentialSiblings<I, J>
+where
+ I: Iterator<Item = DefId>,
+ J: Iterator<Item = DefId>,
+{
+ Unfiltered(I),
+ Filtered(J),
+}
+
+impl<I, J> Iterator for PotentialSiblings<I, J>
+where
+ I: Iterator<Item = DefId>,
+ J: Iterator<Item = DefId>,
+{
+ type Item = DefId;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match *self {
+ PotentialSiblings::Unfiltered(ref mut iter) => iter.next(),
+ PotentialSiblings::Filtered(ref mut iter) => iter.next(),
+ }
+ }
+}
+
+pub trait GraphExt {
+ /// Insert a local impl into the specialization graph. If an existing impl
+ /// conflicts with it (has overlap, but neither specializes the other),
+ /// information about the area of overlap is returned in the `Err`.
+ fn insert(
+ &mut self,
+ tcx: TyCtxt<'_>,
+ impl_def_id: DefId,
+ overlap_mode: OverlapMode,
+ ) -> Result<Option<FutureCompatOverlapError>, OverlapError>;
+
+ /// Insert cached metadata mapping from a child impl back to its parent.
+ fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, parent: DefId, child: DefId);
+}
+
+impl GraphExt for Graph {
+ /// Insert a local impl into the specialization graph. If an existing impl
+ /// conflicts with it (has overlap, but neither specializes the other),
+ /// information about the area of overlap is returned in the `Err`.
+ fn insert(
+ &mut self,
+ tcx: TyCtxt<'_>,
+ impl_def_id: DefId,
+ overlap_mode: OverlapMode,
+ ) -> Result<Option<FutureCompatOverlapError>, OverlapError> {
+ assert!(impl_def_id.is_local());
+
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_def_id = trait_ref.def_id;
+
+ debug!(
+ "insert({:?}): inserting TraitRef {:?} into specialization graph",
+ impl_def_id, trait_ref
+ );
+
+ // If the reference itself contains an earlier error (e.g., due to a
+ // resolution failure), then we just insert the impl at the top level of
+ // the graph and claim that there's no overlap (in order to suppress
+ // bogus errors).
+ if trait_ref.references_error() {
+ debug!(
+ "insert: inserting dummy node for erroneous TraitRef {:?}, \
+ impl_def_id={:?}, trait_def_id={:?}",
+ trait_ref, impl_def_id, trait_def_id
+ );
+
+ self.parent.insert(impl_def_id, trait_def_id);
+ self.children.entry(trait_def_id).or_default().insert_blindly(tcx, impl_def_id);
+ return Ok(None);
+ }
+
+ let mut parent = trait_def_id;
+ let mut last_lint = None;
+ let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), TreatParams::AsInfer);
+
+ // Descend the specialization tree, where `parent` is the current parent node.
+ loop {
+ use self::Inserted::*;
+
+ let insert_result = self.children.entry(parent).or_default().insert(
+ tcx,
+ impl_def_id,
+ simplified,
+ overlap_mode,
+ )?;
+
+ match insert_result {
+ BecameNewSibling(opt_lint) => {
+ last_lint = opt_lint;
+ break;
+ }
+ ReplaceChildren(grand_children_to_be) => {
+ // We currently have
+ //
+ // P
+ // |
+ // G
+ //
+ // and we are inserting the impl N. We want to make it:
+ //
+ // P
+ // |
+ // N
+ // |
+ // G
+
+ // Adjust P's list of children: remove G and then add N.
+ {
+ let siblings = self.children.get_mut(&parent).unwrap();
+ for &grand_child_to_be in &grand_children_to_be {
+ siblings.remove_existing(tcx, grand_child_to_be);
+ }
+ siblings.insert_blindly(tcx, impl_def_id);
+ }
+
+ // Set G's parent to N and N's parent to P.
+ for &grand_child_to_be in &grand_children_to_be {
+ self.parent.insert(grand_child_to_be, impl_def_id);
+ }
+ self.parent.insert(impl_def_id, parent);
+
+ // Add G as N's child.
+ for &grand_child_to_be in &grand_children_to_be {
+ self.children
+ .entry(impl_def_id)
+ .or_default()
+ .insert_blindly(tcx, grand_child_to_be);
+ }
+ break;
+ }
+ ShouldRecurseOn(new_parent) => {
+ parent = new_parent;
+ }
+ }
+ }
+
+ self.parent.insert(impl_def_id, parent);
+ Ok(last_lint)
+ }
+
+ /// Insert cached metadata mapping from a child impl back to its parent.
+ fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'_>, parent: DefId, child: DefId) {
+ if self.parent.insert(child, parent).is_some() {
+ bug!(
+ "When recording an impl from the crate store, information about its parent \
+ was already present."
+ );
+ }
+
+ self.children.entry(parent).or_default().insert_blindly(tcx, child);
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
new file mode 100644
index 000000000..5829a0f92
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -0,0 +1,273 @@
+use crate::infer::{InferCtxt, TyCtxtInferExt};
+use crate::traits::ObligationCause;
+use crate::traits::{TraitEngine, TraitEngineExt};
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
+use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::Span;
+use std::ops::ControlFlow;
+
+/// This method traverses the structure of `ty`, trying to find an
+/// instance of an ADT (i.e. struct or enum) that doesn't implement
+/// the structural-match traits, or a generic type parameter
+/// (which cannot be determined to be structural-match).
+///
+/// The "structure of a type" includes all components that would be
+/// considered when doing a pattern match on a constant of that
+/// type.
+///
+/// * This means this method descends into fields of structs/enums,
+/// and also descends into the inner type `T` of `&T` and `&mut T`
+///
+/// * The traversal doesn't dereference unsafe pointers (`*const T`,
+/// `*mut T`), and it does not visit the type arguments of an
+/// instantiated generic like `PhantomData<T>`.
+///
+/// The reason we do this search is Rust currently require all ADTs
+/// reachable from a constant's type to implement the
+/// structural-match traits, which essentially say that
+/// the implementation of `PartialEq::eq` behaves *equivalently* to a
+/// comparison against the unfolded structure.
+///
+/// For more background on why Rust has this requirement, and issues
+/// that arose when the requirement was not enforced completely, see
+/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
+pub fn search_for_structural_match_violation<'tcx>(
+ span: Span,
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+) -> Option<Ty<'tcx>> {
+ ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: false })
+ .break_value()
+}
+
+/// This method traverses the structure of `ty`, trying to find any
+/// types that are not allowed to be used in a const generic.
+///
+/// This is either because the type does not implement `StructuralEq`
+/// and `StructuralPartialEq`, or because the type is intentionally
+/// not supported in const generics (such as floats and raw pointers,
+/// which are allowed in match blocks).
+pub fn search_for_adt_const_param_violation<'tcx>(
+ span: Span,
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+) -> Option<Ty<'tcx>> {
+ ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), adt_const_param: true })
+ .break_value()
+}
+
+/// This method returns true if and only if `adt_ty` itself has been marked as
+/// eligible for structural-match: namely, if it implements both
+/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
+/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
+///
+/// Note that this does *not* recursively check if the substructure of `adt_ty`
+/// implements the traits.
+fn type_marked_structural<'tcx>(
+ infcx: &InferCtxt<'_, 'tcx>,
+ adt_ty: Ty<'tcx>,
+ cause: ObligationCause<'tcx>,
+) -> bool {
+ let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ // require `#[derive(PartialEq)]`
+ let structural_peq_def_id =
+ infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
+ fulfillment_cx.register_bound(
+ infcx,
+ ty::ParamEnv::empty(),
+ adt_ty,
+ structural_peq_def_id,
+ cause.clone(),
+ );
+ // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
+ // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
+ let structural_teq_def_id =
+ infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
+ fulfillment_cx.register_bound(
+ infcx,
+ ty::ParamEnv::empty(),
+ adt_ty,
+ structural_teq_def_id,
+ cause,
+ );
+
+ // We deliberately skip *reporting* fulfillment errors (via
+ // `report_fulfillment_errors`), for two reasons:
+ //
+ // 1. The error messages would mention `std::marker::StructuralPartialEq`
+ // (a trait which is solely meant as an implementation detail
+ // for now), and
+ //
+ // 2. We are sometimes doing future-incompatibility lints for
+ // now, so we do not want unconditional errors here.
+ fulfillment_cx.select_all_or_error(infcx).is_empty()
+}
+
+/// This implements the traversal over the structure of a given type to try to
+/// find instances of ADTs (specifically structs or enums) that do not implement
+/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
+struct Search<'tcx> {
+ span: Span,
+
+ tcx: TyCtxt<'tcx>,
+
+ /// Tracks ADTs previously encountered during search, so that
+ /// we will not recur on them again.
+ seen: FxHashSet<hir::def_id::DefId>,
+
+ // Additionally deny things that have been allowed in patterns,
+ // but are not allowed in adt const params, such as floats and
+ // fn ptrs.
+ adt_const_param: bool,
+}
+
+impl<'tcx> Search<'tcx> {
+ fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
+ adt_ty.is_structural_eq_shallow(self.tcx)
+ }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
+ type BreakTy = Ty<'tcx>;
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ debug!("Search visiting ty: {:?}", ty);
+
+ let (adt_def, substs) = match *ty.kind() {
+ ty::Adt(adt_def, substs) => (adt_def, substs),
+ ty::Param(_) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::Dynamic(..) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::Foreign(_) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::Opaque(..) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::Projection(..) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::Closure(..) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::Generator(..) | ty::GeneratorWitness(..) => {
+ return ControlFlow::Break(ty);
+ }
+ ty::FnDef(..) => {
+ // Types of formals and return in `fn(_) -> _` are also irrelevant;
+ // so we do not recur into them via `super_visit_with`
+ return ControlFlow::CONTINUE;
+ }
+ ty::Array(_, n)
+ if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
+ {
+ // rust-lang/rust#62336: ignore type of contents
+ // for empty array.
+ return ControlFlow::CONTINUE;
+ }
+ ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => {
+ // These primitive types are always structural match.
+ //
+ // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
+ return ControlFlow::CONTINUE;
+ }
+
+ ty::FnPtr(..) => {
+ if !self.adt_const_param {
+ return ControlFlow::CONTINUE;
+ } else {
+ return ControlFlow::Break(ty);
+ }
+ }
+
+ ty::RawPtr(..) => {
+ if !self.adt_const_param {
+ // structural-match ignores substructure of
+ // `*const _`/`*mut _`, so skip `super_visit_with`.
+ //
+ // For example, if you have:
+ // ```
+ // struct NonStructural;
+ // #[derive(PartialEq, Eq)]
+ // struct T(*const NonStructural);
+ // const C: T = T(std::ptr::null());
+ // ```
+ //
+ // Even though `NonStructural` does not implement `PartialEq`,
+ // structural equality on `T` does not recur into the raw
+ // pointer. Therefore, one can still use `C` in a pattern.
+ return ControlFlow::CONTINUE;
+ } else {
+ return ControlFlow::Break(ty);
+ }
+ }
+
+ ty::Float(_) => {
+ if !self.adt_const_param {
+ return ControlFlow::CONTINUE;
+ } else {
+ return ControlFlow::Break(ty);
+ }
+ }
+
+ ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
+ // First check all contained types and then tell the caller to continue searching.
+ return ty.super_visit_with(self);
+ }
+ ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
+ bug!("unexpected type during structural-match checking: {:?}", ty);
+ }
+ ty::Error(_) => {
+ self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check");
+ // We still want to check other types after encountering an error,
+ // as this may still emit relevant errors.
+ return ControlFlow::CONTINUE;
+ }
+ };
+
+ if !self.seen.insert(adt_def.did()) {
+ debug!("Search already seen adt_def: {:?}", adt_def);
+ return ControlFlow::CONTINUE;
+ }
+
+ if !self.type_marked_structural(ty) {
+ debug!("Search found ty: {:?}", ty);
+ return ControlFlow::Break(ty);
+ }
+
+ // structural-match does not care about the
+ // instantiation of the generics in an ADT (it
+ // instead looks directly at its fields outside
+ // this match), so we skip super_visit_with.
+ //
+ // (Must not recur on substs for `PhantomData<T>` cf
+ // rust-lang/rust#55028 and rust-lang/rust#55837; but also
+ // want to skip substs when only uses of generic are
+ // behind unsafe pointers `*const T`/`*mut T`.)
+
+ // even though we skip super_visit_with, we must recur on
+ // fields of ADT.
+ let tcx = self.tcx;
+ adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| {
+ let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
+ debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
+ ty.visit_with(self)
+ })
+ }
+}
+
+pub fn provide(providers: &mut Providers) {
+ providers.has_structural_eq_impls = |tcx, ty| {
+ tcx.infer_ctxt().enter(|infcx| {
+ let cause = ObligationCause::dummy();
+ type_marked_structural(&infcx, ty, cause)
+ })
+ };
+}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
new file mode 100644
index 000000000..d25006016
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -0,0 +1,368 @@
+use rustc_errors::Diagnostic;
+use rustc_span::Span;
+use smallvec::smallvec;
+use smallvec::SmallVec;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
+use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
+
+use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
+pub use rustc_infer::traits::{self, util::*};
+
+use std::iter;
+
+///////////////////////////////////////////////////////////////////////////
+// `TraitAliasExpander` iterator
+///////////////////////////////////////////////////////////////////////////
+
+/// "Trait alias expansion" is the process of expanding a sequence of trait
+/// references into another sequence by transitively following all trait
+/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
+/// `trait Foo = Bar + Sync;`, and another trait alias
+/// `trait Bar = Read + Write`, then the bounds would expand to
+/// `Read + Write + Sync + Send`.
+/// Expansion is done via a DFS (depth-first search), and the `visited` field
+/// is used to avoid cycles.
+pub struct TraitAliasExpander<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ stack: Vec<TraitAliasExpansionInfo<'tcx>>,
+}
+
+/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
+#[derive(Debug, Clone)]
+pub struct TraitAliasExpansionInfo<'tcx> {
+ pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
+}
+
+impl<'tcx> TraitAliasExpansionInfo<'tcx> {
+ fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
+ Self { path: smallvec![(trait_ref, span)] }
+ }
+
+ /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
+ /// trait aliases.
+ pub fn label_with_exp_info(&self, diag: &mut Diagnostic, top_label: &str, use_desc: &str) {
+ diag.span_label(self.top().1, top_label);
+ if self.path.len() > 1 {
+ for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
+ diag.span_label(*sp, format!("referenced here ({})", use_desc));
+ }
+ }
+ if self.top().1 != self.bottom().1 {
+ // When the trait object is in a return type these two spans match, we don't want
+ // redundant labels.
+ diag.span_label(
+ self.bottom().1,
+ format!("trait alias used in trait object type ({})", use_desc),
+ );
+ }
+ }
+
+ pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> {
+ self.top().0
+ }
+
+ pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
+ self.path.last().unwrap()
+ }
+
+ pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
+ self.path.first().unwrap()
+ }
+
+ fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
+ let mut path = self.path.clone();
+ path.push((trait_ref, span));
+
+ Self { path }
+ }
+}
+
+pub fn expand_trait_aliases<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
+) -> TraitAliasExpander<'tcx> {
+ let items: Vec<_> =
+ trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
+ TraitAliasExpander { tcx, stack: items }
+}
+
+impl<'tcx> TraitAliasExpander<'tcx> {
+ /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
+ /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
+ /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
+ /// trait alias.
+ /// The return value indicates whether `item` should be yielded to the user.
+ fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
+ let tcx = self.tcx;
+ let trait_ref = item.trait_ref();
+ let pred = trait_ref.without_const().to_predicate(tcx);
+
+ debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
+
+ // Don't recurse if this bound is not a trait alias.
+ let is_alias = tcx.is_trait_alias(trait_ref.def_id());
+ if !is_alias {
+ return true;
+ }
+
+ // Don't recurse if this trait alias is already on the stack for the DFS search.
+ let anon_pred = anonymize_predicate(tcx, pred);
+ if item.path.iter().rev().skip(1).any(|&(tr, _)| {
+ anonymize_predicate(tcx, tr.without_const().to_predicate(tcx)) == anon_pred
+ }) {
+ return false;
+ }
+
+ // Get components of trait alias.
+ let predicates = tcx.super_predicates_of(trait_ref.def_id());
+ debug!(?predicates);
+
+ let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
+ pred.subst_supertrait(tcx, &trait_ref)
+ .to_opt_poly_trait_pred()
+ .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
+ });
+ debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
+
+ self.stack.extend(items);
+
+ false
+ }
+}
+
+impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
+ type Item = TraitAliasExpansionInfo<'tcx>;
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.stack.len(), None)
+ }
+
+ fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
+ while let Some(item) = self.stack.pop() {
+ if self.expand(&item) {
+ return Some(item);
+ }
+ }
+ None
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Iterator over def-IDs of supertraits
+///////////////////////////////////////////////////////////////////////////
+
+pub struct SupertraitDefIds<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ stack: Vec<DefId>,
+ visited: FxHashSet<DefId>,
+}
+
+pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> {
+ SupertraitDefIds {
+ tcx,
+ stack: vec![trait_def_id],
+ visited: Some(trait_def_id).into_iter().collect(),
+ }
+}
+
+impl Iterator for SupertraitDefIds<'_> {
+ type Item = DefId;
+
+ fn next(&mut self) -> Option<DefId> {
+ let def_id = self.stack.pop()?;
+ let predicates = self.tcx.super_predicates_of(def_id);
+ let visited = &mut self.visited;
+ self.stack.extend(
+ predicates
+ .predicates
+ .iter()
+ .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
+ .map(|trait_ref| trait_ref.def_id())
+ .filter(|&super_def_id| visited.insert(super_def_id)),
+ );
+ Some(def_id)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Other
+///////////////////////////////////////////////////////////////////////////
+
+/// Instantiate all bound parameters of the impl subject with the given substs,
+/// returning the resulting subject and all obligations that arise.
+/// The obligations are closed under normalization.
+pub fn impl_subject_and_oblig<'a, 'tcx>(
+ selcx: &mut SelectionContext<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ impl_def_id: DefId,
+ impl_substs: SubstsRef<'tcx>,
+) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
+ let subject = selcx.tcx().bound_impl_subject(impl_def_id);
+ let subject = subject.subst(selcx.tcx(), impl_substs);
+ let Normalized { value: subject, obligations: normalization_obligations1 } =
+ super::normalize(selcx, param_env, ObligationCause::dummy(), subject);
+
+ let predicates = selcx.tcx().predicates_of(impl_def_id);
+ let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
+ let Normalized { value: predicates, obligations: normalization_obligations2 } =
+ super::normalize(selcx, param_env, ObligationCause::dummy(), predicates);
+ let impl_obligations =
+ predicates_for_generics(ObligationCause::dummy(), 0, param_env, predicates);
+
+ let impl_obligations = impl_obligations
+ .chain(normalization_obligations1.into_iter())
+ .chain(normalization_obligations2.into_iter());
+
+ (subject, impl_obligations)
+}
+
+pub fn predicates_for_generics<'tcx>(
+ cause: ObligationCause<'tcx>,
+ recursion_depth: usize,
+ param_env: ty::ParamEnv<'tcx>,
+ generic_bounds: ty::InstantiatedPredicates<'tcx>,
+) -> impl Iterator<Item = PredicateObligation<'tcx>> {
+ debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);
+
+ iter::zip(generic_bounds.predicates, generic_bounds.spans).map(move |(predicate, span)| {
+ let cause = match *cause.code() {
+ traits::ItemObligation(def_id) if !span.is_dummy() => traits::ObligationCause::new(
+ cause.span,
+ cause.body_id,
+ traits::BindingObligation(def_id, span),
+ ),
+ _ => cause.clone(),
+ };
+ Obligation { cause, recursion_depth, param_env, predicate }
+ })
+}
+
+pub fn predicate_for_trait_ref<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ recursion_depth: usize,
+) -> PredicateObligation<'tcx> {
+ Obligation {
+ cause,
+ param_env,
+ recursion_depth,
+ predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+ }
+}
+
+pub fn predicate_for_trait_def<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ cause: ObligationCause<'tcx>,
+ trait_def_id: DefId,
+ recursion_depth: usize,
+ self_ty: Ty<'tcx>,
+ params: &[GenericArg<'tcx>],
+) -> PredicateObligation<'tcx> {
+ let trait_ref =
+ ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) };
+ predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth)
+}
+
+/// Casts a trait reference into a reference to one of its super
+/// traits; returns `None` if `target_trait_def_id` is not a
+/// supertrait.
+pub fn upcast_choices<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ source_trait_ref: ty::PolyTraitRef<'tcx>,
+ target_trait_def_id: DefId,
+) -> Vec<ty::PolyTraitRef<'tcx>> {
+ if source_trait_ref.def_id() == target_trait_def_id {
+ return vec![source_trait_ref]; // Shortcut the most common case.
+ }
+
+ supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
+}
+
+/// Given a trait `trait_ref`, returns the number of vtable entries
+/// that come from `trait_ref`, excluding its supertraits. Used in
+/// computing the vtable base for an upcast trait of a trait object.
+pub fn count_own_vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+) -> usize {
+ let existential_trait_ref =
+ trait_ref.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+ let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
+ tcx.own_existential_vtable_entries(existential_trait_ref).len()
+}
+
+/// Given an upcast trait object described by `object`, returns the
+/// index of the method `method_def_id` (which should be part of
+/// `object.upcast_trait_ref`) within the vtable for `object`.
+pub fn get_vtable_index_of_object_method<'tcx, N>(
+ tcx: TyCtxt<'tcx>,
+ object: &super::ImplSourceObjectData<'tcx, N>,
+ method_def_id: DefId,
+) -> Option<usize> {
+ let existential_trait_ref = object
+ .upcast_trait_ref
+ .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+ let existential_trait_ref = tcx.erase_regions(existential_trait_ref);
+
+ // Count number of methods preceding the one we are selecting and
+ // add them to the total offset.
+ if let Some(index) = tcx
+ .own_existential_vtable_entries(existential_trait_ref)
+ .iter()
+ .copied()
+ .position(|def_id| def_id == method_def_id)
+ {
+ Some(object.vtable_base + index)
+ } else {
+ None
+ }
+}
+
+pub fn closure_trait_ref_and_return_type<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_trait_def_id: DefId,
+ self_ty: Ty<'tcx>,
+ sig: ty::PolyFnSig<'tcx>,
+ tuple_arguments: TupleArgumentsFlag,
+) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
+ let arguments_tuple = match tuple_arguments {
+ TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
+ TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()),
+ };
+ debug_assert!(!self_ty.has_escaping_bound_vars());
+ let trait_ref = ty::TraitRef {
+ def_id: fn_trait_def_id,
+ substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]),
+ };
+ sig.map_bound(|sig| (trait_ref, sig.output()))
+}
+
+pub fn generator_trait_ref_and_outputs<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_trait_def_id: DefId,
+ self_ty: Ty<'tcx>,
+ sig: ty::PolyGenSig<'tcx>,
+) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
+ debug_assert!(!self_ty.has_escaping_bound_vars());
+ let trait_ref = ty::TraitRef {
+ def_id: fn_trait_def_id,
+ substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]),
+ };
+ sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty))
+}
+
+pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
+ assoc_item.defaultness(tcx).is_final()
+ && tcx.impl_defaultness(assoc_item.container_id(tcx)).is_final()
+}
+
+pub enum TupleArgumentsFlag {
+ Yes,
+ No,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
new file mode 100644
index 000000000..414857f0a
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -0,0 +1,888 @@
+use crate::infer::InferCtxt;
+use crate::traits;
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_span::Span;
+
+use std::iter;
+/// Returns the set of obligations needed to make `arg` well-formed.
+/// If `arg` contains unresolved inference variables, this may include
+/// further WF obligations. However, if `arg` IS an unresolved
+/// inference variable, returns `None`, because we are not able to
+/// make any progress at all. This is to prevent "livelock" where we
+/// say "$0 is WF if $0 is WF".
+pub fn obligations<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ recursion_depth: usize,
+ arg: GenericArg<'tcx>,
+ span: Span,
+) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
+ // Handle the "livelock" case (see comment above) by bailing out if necessary.
+ let arg = match arg.unpack() {
+ GenericArgKind::Type(ty) => {
+ match ty.kind() {
+ ty::Infer(ty::TyVar(_)) => {
+ let resolved_ty = infcx.shallow_resolve(ty);
+ if resolved_ty == ty {
+ // No progress, bail out to prevent "livelock".
+ return None;
+ }
+
+ resolved_ty
+ }
+ _ => ty,
+ }
+ .into()
+ }
+ GenericArgKind::Const(ct) => {
+ match ct.kind() {
+ ty::ConstKind::Infer(infer) => {
+ let resolved = infcx.shallow_resolve(infer);
+ if resolved == infer {
+ // No progress.
+ return None;
+ }
+
+ infcx
+ .tcx
+ .mk_const(ty::ConstS { kind: ty::ConstKind::Infer(resolved), ty: ct.ty() })
+ }
+ _ => ct,
+ }
+ .into()
+ }
+ // There is nothing we have to do for lifetimes.
+ GenericArgKind::Lifetime(..) => return Some(Vec::new()),
+ };
+
+ let mut wf = WfPredicates {
+ tcx: infcx.tcx,
+ param_env,
+ body_id,
+ span,
+ out: vec![],
+ recursion_depth,
+ item: None,
+ };
+ wf.compute(arg);
+ debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
+
+ let result = wf.normalize(infcx);
+ debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result);
+ Some(result)
+}
+
+/// 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
+/// if `Bar: Eq`.
+pub fn trait_obligations<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ trait_pred: &ty::TraitPredicate<'tcx>,
+ span: Span,
+ item: &'tcx hir::Item<'tcx>,
+) -> Vec<traits::PredicateObligation<'tcx>> {
+ let mut wf = WfPredicates {
+ tcx: infcx.tcx,
+ param_env,
+ body_id,
+ span,
+ out: vec![],
+ recursion_depth: 0,
+ item: Some(item),
+ };
+ wf.compute_trait_pred(trait_pred, Elaborate::All);
+ debug!(obligations = ?wf.out);
+ wf.normalize(infcx)
+}
+
+pub fn predicate_obligations<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ predicate: ty::Predicate<'tcx>,
+ span: Span,
+) -> Vec<traits::PredicateObligation<'tcx>> {
+ let mut wf = WfPredicates {
+ tcx: infcx.tcx,
+ param_env,
+ body_id,
+ span,
+ out: vec![],
+ recursion_depth: 0,
+ item: None,
+ };
+
+ // It's ok to skip the binder here because wf code is prepared for it
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(t) => {
+ wf.compute_trait_pred(&t, Elaborate::None);
+ }
+ ty::PredicateKind::RegionOutlives(..) => {}
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+ wf.compute(ty.into());
+ }
+ ty::PredicateKind::Projection(t) => {
+ wf.compute_projection(t.projection_ty);
+ wf.compute(match t.term {
+ ty::Term::Ty(ty) => ty.into(),
+ ty::Term::Const(c) => c.into(),
+ })
+ }
+ ty::PredicateKind::WellFormed(arg) => {
+ wf.compute(arg);
+ }
+ ty::PredicateKind::ObjectSafe(_) => {}
+ ty::PredicateKind::ClosureKind(..) => {}
+ ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
+ wf.compute(a.into());
+ wf.compute(b.into());
+ }
+ ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+ wf.compute(a.into());
+ wf.compute(b.into());
+ }
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
+ wf.out.extend(obligations);
+
+ for arg in uv.substs.iter() {
+ wf.compute(arg);
+ }
+ }
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ wf.compute(c1.into());
+ wf.compute(c2.into());
+ }
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+ bug!("TypeWellFormedFromEnv is only used for Chalk")
+ }
+ }
+
+ wf.normalize(infcx)
+}
+
+struct WfPredicates<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ body_id: hir::HirId,
+ span: Span,
+ out: Vec<traits::PredicateObligation<'tcx>>,
+ recursion_depth: usize,
+ item: Option<&'tcx hir::Item<'tcx>>,
+}
+
+/// Controls whether we "elaborate" supertraits and so forth on the WF
+/// predicates. This is a kind of hack to address #43784. The
+/// underlying problem in that issue was a trait structure like:
+///
+/// ```ignore (illustrative)
+/// trait Foo: Copy { }
+/// trait Bar: Foo { }
+/// impl<T: Bar> Foo for T { }
+/// impl<T> Bar for T { }
+/// ```
+///
+/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but
+/// we decide that this is true because `T: Bar` is in the
+/// where-clauses (and we can elaborate that to include `T:
+/// Copy`). This wouldn't be a problem, except that when we check the
+/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo`
+/// impl. And so nowhere did we check that `T: Copy` holds!
+///
+/// To resolve this, we elaborate the WF requirements that must be
+/// proven when checking impls. This means that (e.g.) the `impl Bar
+/// for T` will be forced to prove not only that `T: Foo` but also `T:
+/// Copy` (which it won't be able to do, because there is no `Copy`
+/// impl for `T`).
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+enum Elaborate {
+ All,
+ None,
+}
+
+fn extend_cause_with_original_assoc_item_obligation<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: &ty::TraitRef<'tcx>,
+ item: Option<&hir::Item<'tcx>>,
+ cause: &mut traits::ObligationCause<'tcx>,
+ pred: ty::Predicate<'tcx>,
+) {
+ debug!(
+ "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
+ trait_ref, item, cause, pred
+ );
+ let (items, impl_def_id) = match item {
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
+ _ => return,
+ };
+ let fix_span =
+ |impl_item_ref: &hir::ImplItemRef| match tcx.hir().impl_item(impl_item_ref.id).kind {
+ hir::ImplItemKind::Const(ty, _) | hir::ImplItemKind::TyAlias(ty) => ty.span,
+ _ => impl_item_ref.span,
+ };
+
+ // It is fine to skip the binder as we don't care about regions here.
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Projection(proj) => {
+ // The obligation comes not from the current `impl` nor the `trait` being implemented,
+ // but rather from a "second order" obligation, where an associated type has a
+ // projection coming from another associated type. See
+ // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
+ // `traits-assoc-type-in-supertrait-bad.rs`.
+ if let Some(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.item_def_id)
+ && let Some(impl_item_span) = items
+ .iter()
+ .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .map(fix_span)
+ {
+ cause.span = impl_item_span;
+ }
+ }
+ ty::PredicateKind::Trait(pred) => {
+ // An associated item obligation born out of the `trait` failed to be met. An example
+ // 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::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind()
+ && let Some(&impl_item_id) =
+ tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
+ && let Some(impl_item_span) = items
+ .iter()
+ .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .map(fix_span)
+ {
+ cause.span = impl_item_span;
+ }
+ }
+ _ => {}
+ }
+}
+
+impl<'tcx> WfPredicates<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
+ traits::ObligationCause::new(self.span, self.body_id, code)
+ }
+
+ fn normalize(self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<traits::PredicateObligation<'tcx>> {
+ let cause = self.cause(traits::WellFormed(None));
+ let param_env = self.param_env;
+ let mut obligations = Vec::with_capacity(self.out.len());
+ for mut obligation in self.out {
+ assert!(!obligation.has_escaping_bound_vars());
+ let mut selcx = traits::SelectionContext::new(infcx);
+ // Don't normalize the whole obligation, the param env is either
+ // already normalized, or we're currently normalizing the
+ // param_env. Either way we should only normalize the predicate.
+ let normalized_predicate = traits::project::normalize_with_depth_to(
+ &mut selcx,
+ param_env,
+ cause.clone(),
+ self.recursion_depth,
+ obligation.predicate,
+ &mut obligations,
+ );
+ obligation.predicate = normalized_predicate;
+ obligations.push(obligation);
+ }
+ obligations
+ }
+
+ /// 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) {
+ let tcx = self.tcx;
+ let trait_ref = &trait_pred.trait_ref;
+
+ // if the trait predicate is not const, the wf obligations should not be const as well.
+ let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
+ self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
+ } else {
+ self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
+ };
+
+ debug!("compute_trait_pred obligations {:?}", obligations);
+ let param_env = self.param_env;
+ let depth = self.recursion_depth;
+
+ let item = self.item;
+
+ let extend = |traits::PredicateObligation { predicate, mut cause, .. }| {
+ if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() {
+ cause = cause.derived_cause(
+ parent_trait_pred,
+ traits::ObligationCauseCode::DerivedObligation,
+ );
+ }
+ extend_cause_with_original_assoc_item_obligation(
+ tcx, trait_ref, item, &mut cause, predicate,
+ );
+ traits::Obligation::with_depth(cause, depth, param_env, predicate)
+ };
+
+ if let Elaborate::All = elaborate {
+ let implied_obligations = traits::util::elaborate_obligations(tcx, obligations);
+ let implied_obligations = implied_obligations.map(extend);
+ self.out.extend(implied_obligations);
+ } else {
+ self.out.extend(obligations);
+ }
+
+ let tcx = self.tcx();
+ self.out.extend(
+ trait_ref
+ .substs
+ .iter()
+ .enumerate()
+ .filter(|(_, arg)| {
+ matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+ })
+ .filter(|(_, arg)| !arg.has_escaping_bound_vars())
+ .map(|(i, arg)| {
+ let mut cause = traits::ObligationCause::misc(self.span, self.body_id);
+ // The first subst is the self ty - use the correct span for it.
+ if i == 0 {
+ if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) =
+ item.map(|i| &i.kind)
+ {
+ cause.span = self_ty.span;
+ }
+ }
+ traits::Obligation::with_depth(
+ cause,
+ depth,
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
+ )
+ }),
+ );
+ }
+
+ /// Pushes the obligations required for `trait_ref::Item` to be WF
+ /// into `self.out`.
+ fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
+ // A projection is well-formed if
+ //
+ // (a) its predicates hold (*)
+ // (b) its substs are wf
+ //
+ // (*) The predicates of an associated type include the predicates of
+ // the trait that it's contained in. For example, given
+ //
+ // trait A<T>: Clone {
+ // type X where T: Copy;
+ // }
+ //
+ // The predicates of `<() as A<i32>>::X` are:
+ // [
+ // `(): Sized`
+ // `(): Clone`
+ // `(): A<i32>`
+ // `i32: Sized`
+ // `i32: Clone`
+ // `i32: Copy`
+ // ]
+ let obligations = self.nominal_obligations(data.item_def_id, data.substs);
+ self.out.extend(obligations);
+
+ let tcx = self.tcx();
+ let cause = self.cause(traits::WellFormed(None));
+ let param_env = self.param_env;
+ let depth = self.recursion_depth;
+
+ self.out.extend(
+ data.substs
+ .iter()
+ .filter(|arg| {
+ matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+ })
+ .filter(|arg| !arg.has_escaping_bound_vars())
+ .map(|arg| {
+ traits::Obligation::with_depth(
+ cause.clone(),
+ depth,
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
+ )
+ }),
+ );
+ }
+
+ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
+ if !subty.has_escaping_bound_vars() {
+ let cause = self.cause(cause);
+ let trait_ref = ty::TraitRef {
+ def_id: self.tcx.require_lang_item(LangItem::Sized, None),
+ substs: self.tcx.mk_substs_trait(subty, &[]),
+ };
+ self.out.push(traits::Obligation::with_depth(
+ cause,
+ self.recursion_depth,
+ self.param_env,
+ ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
+ ));
+ }
+ }
+
+ /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
+ fn compute(&mut self, arg: GenericArg<'tcx>) {
+ let mut walker = arg.walk();
+ let param_env = self.param_env;
+ let depth = self.recursion_depth;
+ while let Some(arg) = walker.next() {
+ let ty = match arg.unpack() {
+ GenericArgKind::Type(ty) => ty,
+
+ // No WF constraints for lifetimes being present, any outlives
+ // obligations are handled by the parent (e.g. `ty::Ref`).
+ GenericArgKind::Lifetime(_) => continue,
+
+ GenericArgKind::Const(constant) => {
+ match constant.kind() {
+ ty::ConstKind::Unevaluated(uv) => {
+ let obligations = self.nominal_obligations(uv.def.did, uv.substs);
+ self.out.extend(obligations);
+
+ let predicate =
+ ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
+ .to_predicate(self.tcx());
+ let cause = self.cause(traits::WellFormed(None));
+ self.out.push(traits::Obligation::with_depth(
+ cause,
+ self.recursion_depth,
+ self.param_env,
+ predicate,
+ ));
+ }
+ ty::ConstKind::Infer(_) => {
+ let cause = self.cause(traits::WellFormed(None));
+
+ self.out.push(traits::Obligation::with_depth(
+ cause,
+ self.recursion_depth,
+ self.param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(constant.into()))
+ .to_predicate(self.tcx()),
+ ));
+ }
+ ty::ConstKind::Error(_)
+ | ty::ConstKind::Param(_)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Placeholder(..) => {
+ // These variants are trivially WF, so nothing to do here.
+ }
+ ty::ConstKind::Value(..) => {
+ // FIXME: Enforce that values are structurally-matchable.
+ }
+ }
+ continue;
+ }
+ };
+
+ match *ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(..)
+ | ty::Uint(..)
+ | ty::Float(..)
+ | ty::Error(_)
+ | ty::Str
+ | ty::GeneratorWitness(..)
+ | ty::Never
+ | ty::Param(_)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Foreign(..) => {
+ // WfScalar, WfParameter, etc
+ }
+
+ // Can only infer to `ty::Int(_) | ty::Uint(_)`.
+ ty::Infer(ty::IntVar(_)) => {}
+
+ // Can only infer to `ty::Float(_)`.
+ ty::Infer(ty::FloatVar(_)) => {}
+
+ ty::Slice(subty) => {
+ self.require_sized(subty, traits::SliceOrArrayElem);
+ }
+
+ ty::Array(subty, _) => {
+ self.require_sized(subty, traits::SliceOrArrayElem);
+ // Note that we handle the len is implicitly checked while walking `arg`.
+ }
+
+ ty::Tuple(ref tys) => {
+ if let Some((_last, rest)) = tys.split_last() {
+ for &elem in rest {
+ self.require_sized(elem, traits::TupleElem);
+ }
+ }
+ }
+
+ ty::RawPtr(_) => {
+ // Simple cases that are WF if their type args are WF.
+ }
+
+ ty::Projection(data) => {
+ walker.skip_current_subtree(); // Subtree handled by compute_projection.
+ self.compute_projection(data);
+ }
+
+ ty::Adt(def, substs) => {
+ // WfNominalType
+ let obligations = self.nominal_obligations(def.did(), substs);
+ self.out.extend(obligations);
+ }
+
+ ty::FnDef(did, substs) => {
+ let obligations = self.nominal_obligations(did, substs);
+ self.out.extend(obligations);
+ }
+
+ ty::Ref(r, rty, _) => {
+ // WfReference
+ if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
+ let cause = self.cause(traits::ReferenceOutlivesReferent(ty));
+ self.out.push(traits::Obligation::with_depth(
+ cause,
+ depth,
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+ ty::OutlivesPredicate(rty, r),
+ ))
+ .to_predicate(self.tcx()),
+ ));
+ }
+ }
+
+ ty::Generator(did, substs, ..) => {
+ // Walk ALL the types in the generator: 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.
+ let obligations = self.nominal_obligations(did, substs);
+ self.out.extend(obligations);
+ }
+
+ ty::Closure(did, substs) => {
+ // Only check the upvar types for WF, not the rest
+ // of the types within. This is needed because we
+ // capture the signature and it may not be WF
+ // without the implied bounds. Consider a closure
+ // like `|x: &'a T|` -- it may be that `T: 'a` is
+ // not known to hold in the creator's context (and
+ // indeed the closure may not be invoked by its
+ // creator, but rather turned to someone who *can*
+ // verify that).
+ //
+ // The special treatment of closures here really
+ // ought not to be necessary either; the problem
+ // is related to #25860 -- there is no way for us
+ // to express a fn type complete with the implied
+ // bounds that it is assuming. I think in reality
+ // the WF rules around fn are a bit messed up, and
+ // that is the rot problem: `fn(&'a T)` should
+ // probably always be WF, because it should be
+ // shorthand for something like `where(T: 'a) {
+ // fn(&'a T) }`, as discussed in #25860.
+ walker.skip_current_subtree(); // subtree handled below
+ // FIXME(eddyb) add the type to `walker` instead of recursing.
+ self.compute(substs.as_closure().tupled_upvars_ty().into());
+ // Note that we cannot skip the generic types
+ // types. Normally, within the fn
+ // body where they are created, the generics will
+ // always be WF, and outside of that fn body we
+ // are not directly inspecting closure types
+ // anyway, except via auto trait matching (which
+ // only inspects the upvar types).
+ // But when a closure is part of a type-alias-impl-trait
+ // then the function that created the defining site may
+ // have had more bounds available than the type alias
+ // specifies. This may cause us to have a closure in the
+ // hidden type that is not actually well formed and
+ // can cause compiler crashes when the user abuses unsafe
+ // code to procure such a closure.
+ // See src/test/ui/type-alias-impl-trait/wf_check_closures.rs
+ let obligations = self.nominal_obligations(did, substs);
+ self.out.extend(obligations);
+ }
+
+ ty::FnPtr(_) => {
+ // let the loop iterate into the argument/return
+ // types appearing in the fn signature
+ }
+
+ ty::Opaque(did, substs) => {
+ // All of the requirements on type parameters
+ // have already been checked for `impl Trait` in
+ // return position. We do need to check type-alias-impl-trait though.
+ if ty::is_impl_trait_defn(self.tcx, did).is_none() {
+ let obligations = self.nominal_obligations(did, substs);
+ self.out.extend(obligations);
+ }
+ }
+
+ ty::Dynamic(data, r) => {
+ // WfObject
+ //
+ // Here, we defer WF checking due to higher-ranked
+ // regions. This is perhaps not ideal.
+ self.from_object_ty(ty, data, r);
+
+ // FIXME(#27579) RFC also considers adding trait
+ // obligations that don't refer to Self and
+ // checking those
+
+ let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
+
+ if !defer_to_coercion {
+ let cause = self.cause(traits::WellFormed(None));
+ let component_traits = data.auto_traits().chain(data.principal_def_id());
+ let tcx = self.tcx();
+ self.out.extend(component_traits.map(|did| {
+ traits::Obligation::with_depth(
+ cause.clone(),
+ depth,
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did))
+ .to_predicate(tcx),
+ )
+ }));
+ }
+ }
+
+ // Inference variables are the complicated case, since we don't
+ // know what type they are. We do two things:
+ //
+ // 1. Check if they have been resolved, and if so proceed with
+ // THAT type.
+ // 2. If not, we've at least simplified things (e.g., we went
+ // from `Vec<$0>: WF` to `$0: WF`), so we can
+ // register a pending obligation and keep
+ // moving. (Goal is that an "inductive hypothesis"
+ // is satisfied to ensure termination.)
+ // See also the comment on `fn obligations`, describing "livelock"
+ // prevention, which happens before this can be reached.
+ ty::Infer(_) => {
+ let cause = self.cause(traits::WellFormed(None));
+ self.out.push(traits::Obligation::with_depth(
+ cause,
+ self.recursion_depth,
+ param_env,
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))
+ .to_predicate(self.tcx()),
+ ));
+ }
+ }
+ }
+ }
+
+ #[instrument(level = "debug", skip(self))]
+ fn nominal_obligations_inner(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ remap_constness: bool,
+ ) -> Vec<traits::PredicateObligation<'tcx>> {
+ let predicates = self.tcx.predicates_of(def_id);
+ let mut origins = vec![def_id; predicates.predicates.len()];
+ let mut head = predicates;
+ while let Some(parent) = head.parent {
+ head = self.tcx.predicates_of(parent);
+ origins.extend(iter::repeat(parent).take(head.predicates.len()));
+ }
+
+ let predicates = predicates.instantiate(self.tcx, substs);
+ trace!("{:#?}", predicates);
+ debug_assert_eq!(predicates.predicates.len(), origins.len());
+
+ iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
+ .map(|((mut pred, span), origin_def_id)| {
+ let code = if span.is_dummy() {
+ traits::MiscObligation
+ } else {
+ traits::BindingObligation(origin_def_id, span)
+ };
+ let cause = self.cause(code);
+ if remap_constness {
+ pred = pred.without_const(self.tcx);
+ }
+ traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
+ })
+ .filter(|pred| !pred.has_escaping_bound_vars())
+ .collect()
+ }
+
+ fn nominal_obligations(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ ) -> Vec<traits::PredicateObligation<'tcx>> {
+ self.nominal_obligations_inner(def_id, substs, false)
+ }
+
+ fn nominal_obligations_without_const(
+ &mut self,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ ) -> Vec<traits::PredicateObligation<'tcx>> {
+ self.nominal_obligations_inner(def_id, substs, true)
+ }
+
+ fn from_object_ty(
+ &mut self,
+ ty: Ty<'tcx>,
+ data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ region: ty::Region<'tcx>,
+ ) {
+ // Imagine a type like this:
+ //
+ // trait Foo { }
+ // trait Bar<'c> : 'c { }
+ //
+ // &'b (Foo+'c+Bar<'d>)
+ // ^
+ //
+ // In this case, the following relationships must hold:
+ //
+ // 'b <= 'c
+ // 'd <= 'c
+ //
+ // The first conditions is due to the normal region pointer
+ // rules, which say that a reference cannot outlive its
+ // referent.
+ //
+ // The final condition may be a bit surprising. In particular,
+ // you may expect that it would have been `'c <= 'd`, since
+ // usually lifetimes of outer things are conservative
+ // approximations for inner things. However, it works somewhat
+ // differently with trait objects: here the idea is that if the
+ // user specifies a region bound (`'c`, in this case) it is the
+ // "master bound" that *implies* that bounds from other traits are
+ // all met. (Remember that *all bounds* in a type like
+ // `Foo+Bar+Zed` must be met, not just one, hence if we write
+ // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
+ // 'y.)
+ //
+ // Note: in fact we only permit builtin traits, not `Bar<'d>`, I
+ // am looking forward to the future here.
+ if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
+ let implicit_bounds = object_region_bounds(self.tcx, data);
+
+ let explicit_bound = region;
+
+ self.out.reserve(implicit_bounds.len());
+ for implicit_bound in implicit_bounds {
+ let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
+ let outlives =
+ ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
+ self.out.push(traits::Obligation::with_depth(
+ cause,
+ self.recursion_depth,
+ self.param_env,
+ outlives.to_predicate(self.tcx),
+ ));
+ }
+ }
+ }
+}
+
+/// Given an object type like `SomeTrait + Send`, computes the lifetime
+/// bounds that must hold on the elided self type. These are derived
+/// from the declarations of `SomeTrait`, `Send`, and friends -- if
+/// they declare `trait SomeTrait : 'static`, for example, then
+/// `'static` would appear in the list. The hard work is done by
+/// `infer::required_region_bounds`, see that for more information.
+pub fn object_region_bounds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ existential_predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+) -> Vec<ty::Region<'tcx>> {
+ // Since we don't actually *know* the self type for an object,
+ // this "open(err)" serves as a kind of dummy standin -- basically
+ // a placeholder type.
+ let open_ty = tcx.mk_ty_infer(ty::FreshTy(0));
+
+ let predicates = existential_predicates.iter().filter_map(|predicate| {
+ if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() {
+ None
+ } else {
+ Some(predicate.with_self_ty(tcx, open_ty))
+ }
+ });
+
+ required_region_bounds(tcx, open_ty, predicates)
+}
+
+/// Given a set of predicates that apply to an object type, returns
+/// the region bounds that the (erased) `Self` type must
+/// outlive. Precisely *because* the `Self` type is erased, the
+/// parameter `erased_self_ty` must be supplied to indicate what type
+/// has been used to represent `Self` in the predicates
+/// themselves. This should really be a unique type; `FreshTy(0)` is a
+/// popular choice.
+///
+/// N.B., in some cases, particularly around higher-ranked bounds,
+/// this function returns a kind of conservative approximation.
+/// That is, all regions returned by this function are definitely
+/// required, but there may be other region bounds that are not
+/// returned, as well as requirements like `for<'a> T: 'a`.
+///
+/// Requires that trait definitions have been processed so that we can
+/// elaborate predicates and walk supertraits.
+#[instrument(skip(tcx, predicates), level = "debug")]
+pub(crate) fn required_region_bounds<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ erased_self_ty: Ty<'tcx>,
+ predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+) -> Vec<ty::Region<'tcx>> {
+ assert!(!erased_self_ty.has_escaping_bound_vars());
+
+ traits::elaborate_predicates(tcx, predicates)
+ .filter_map(|obligation| {
+ debug!(?obligation);
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
+ // Search for a bound of the form `erased_self_ty
+ // : 'a`, but be wary of something like `for<'a>
+ // erased_self_ty : 'a` (we interpret a
+ // higher-ranked bound like that as 'static,
+ // though at present the code in `fulfill.rs`
+ // considers such bounds to be unsatisfiable, so
+ // it's kind of a moot point since you could never
+ // construct such an object, but this seems
+ // correct even if that code changes).
+ if t == &erased_self_ty && !r.has_escaping_bound_vars() {
+ Some(*r)
+ } else {
+ None
+ }
+ }
+ }
+ })
+ .collect()
+}