1use std::fmt::Debug;
23use rustc_hir::attrs::lang_items::LangItem;
4use rustc_hir::def_id::DefId;
5pub use rustc_infer::infer::*;
6use rustc_infer::traits::TraitErrors;
7use rustc_macros::extension;
8use rustc_middle::arena::ArenaAllocatable;
9use rustc_middle::infer::canonical::{
10Canonical, CanonicalQueryInput, CanonicalQueryResponse, QueryResponse,
11};
12use rustc_middle::traits::query::NoSolution;
13use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable, Upcast};
14use rustc_span::DUMMY_SP;
15use tracing::instrument;
1617use crate::infer::at::ToTrace;
18use crate::traits::query::evaluate_obligation::InferCtxtExtas _;
19use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt};
2021impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn can_eq<T: ToTrace<'tcx>>(&self, param_env: ty::ParamEnv<'tcx>, a: T,
b: T) -> bool {
self.probe(|_|
{
let ocx = ObligationCtxt::new(self);
let Ok(()) =
ocx.eq(&ObligationCause::dummy(), param_env, a,
b) else { return false; };
ocx.try_evaluate_obligations().no_errors()
})
}
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
let copy_def_id =
self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty,
copy_def_id)
}
fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
let clone_def_id =
self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty,
clone_def_id)
}
fn type_is_use_cloned_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
let use_cloned_def_id =
self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty,
use_cloned_def_id)
}
fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> bool {
let lang_item = self.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty,
lang_item)
}
#[doc =
" Check whether a `ty` implements given trait(trait_def_id) without side-effects."]
#[doc = ""]
#[doc = " The inputs are:"]
#[doc = ""]
#[doc = " - the def-id of the trait"]
#[doc = " - the type parameters of the trait, including the self-type"]
#[doc = " - the parameter environment"]
#[doc = ""]
#[doc = " Invokes `evaluate_obligation`, so in the event that evaluating"]
#[doc =
" `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned."]
#[doc = ""]
#[doc =
" `type_implements_trait` is a convenience function for simple cases like"]
#[doc = ""]
#[doc = " ```ignore (illustrative)"]
#[doc =
" let copy_trait = infcx.tcx.require_lang_item(LangItem::Copy, span);"]
#[doc =
" let implements_copy = infcx.type_implements_trait(copy_trait, [ty], param_env)"]
#[doc = " .must_apply_modulo_regions();"]
#[doc = " ```"]
#[doc = ""]
#[doc =
" In most cases you should instead create an [Obligation] and check whether"]
#[doc =
" it holds via [`evaluate_obligation`] or one of its helper functions like"]
#[doc =
" [`predicate_must_hold_modulo_regions`], because it properly handles higher ranked traits"]
#[doc =
" and it is more convenient and safer when your `params` are inside a [`Binder`]."]
#[doc = ""]
#[doc = " [Obligation]: traits::Obligation"]
#[doc =
" [`evaluate_obligation`]: crate::traits::query::evaluate_obligation::InferCtxtExt::evaluate_obligation"]
#[doc =
" [`predicate_must_hold_modulo_regions`]: crate::traits::query::evaluate_obligation::InferCtxtExt::predicate_must_hold_modulo_regions"]
#[doc = " [`Binder`]: ty::Binder"]
fn type_implements_trait(&self, trait_def_id: DefId,
params: impl IntoIterator<Item : Into<GenericArg<'tcx>>>,
param_env: ty::ParamEnv<'tcx>) -> traits::EvaluationResult {
{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("type_implements_trait",
"rustc_trait_selection::infer", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/infer.rs"),
::tracing_core::__macro_support::Option::Some(88u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::infer"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("trait_def_id")
}> =
::tracing::__macro_support::FieldName::new("trait_def_id");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("param_env")
}> =
::tracing::__macro_support::FieldName::new("param_env");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&trait_def_id)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(¶m_env)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
(move ||
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy
:: needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: traits::EvaluationResult =
loop {};
return __tracing_attr_fake_return;
}
{
let trait_ref =
ty::TraitRef::new(self.tcx, trait_def_id, params);
let obligation =
traits::Obligation {
cause: traits::ObligationCause::dummy(),
param_env,
recursion_depth: 0,
predicate: trait_ref.upcast(self.tcx),
};
self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
}
})();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/infer.rs:88",
"rustc_trait_selection::infer", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/infer.rs"),
::tracing_core::__macro_support::Option::Some(88u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::infer"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("return")
}> =
::tracing::__macro_support::FieldName::new("return");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
x
}
#[doc =
" Returns `Some` if a type implements a trait shallowly, without side-effects,"]
#[doc =
" along with any errors that would have been reported upon further obligation"]
#[doc = " processing."]
#[doc = ""]
#[doc =
" - If this returns `Some([])`, then the trait holds modulo regions."]
#[doc =
" - If this returns `Some([errors..])`, then the trait has an impl for"]
#[doc = " the self type, but some nested obligations do not hold."]
#[doc =
" - If this returns `None`, no implementation that applies could be found."]
fn type_implements_trait_shallow(&self, trait_def_id: DefId, ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Option<TraitErrors<traits::FulfillmentError<'tcx>>> {
self.probe(|_snapshot|
{
let ocx = ObligationCtxt::new_with_diagnostics(self);
ocx.register_obligation(Obligation::new(self.tcx,
ObligationCause::dummy(), param_env,
ty::TraitRef::new(self.tcx, trait_def_id, [ty])));
let errors = ocx.try_evaluate_obligations();
for error in &errors {
let Some(trait_clause) =
error.obligation.predicate.as_trait_clause() else {
continue;
};
let Some(bound_ty) =
trait_clause.self_ty().no_bound_vars() else { continue };
if trait_clause.def_id() == trait_def_id &&
ocx.eq(&ObligationCause::dummy(), param_env, bound_ty,
ty).is_ok() {
return None;
}
}
Some(errors)
})
}
}#[extension(pub trait InferCtxtExt<'tcx>)]22impl<'tcx> InferCtxt<'tcx> {
23fn can_eq<T: ToTrace<'tcx>>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool {
24self.probe(|_| {
25let ocx = ObligationCtxt::new(self);
26let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else {
27return false;
28 };
29ocx.try_evaluate_obligations().no_errors()
30 })
31 }
3233fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
34let ty = self.resolve_vars_if_possible(ty);
35let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP);
36 traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id)
37 }
3839fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
40let ty = self.resolve_vars_if_possible(ty);
41let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP);
42 traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id)
43 }
4445fn type_is_use_cloned_modulo_regions(
46&self,
47 param_env: ty::ParamEnv<'tcx>,
48 ty: Ty<'tcx>,
49 ) -> bool {
50let ty = self.resolve_vars_if_possible(ty);
51let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP);
52 traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id)
53 }
5455fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
56let lang_item = self.tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
57 traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item)
58 }
5960/// Check whether a `ty` implements given trait(trait_def_id) without side-effects.
61 ///
62 /// The inputs are:
63 ///
64 /// - the def-id of the trait
65 /// - the type parameters of the trait, including the self-type
66 /// - the parameter environment
67 ///
68 /// Invokes `evaluate_obligation`, so in the event that evaluating
69 /// `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned.
70 ///
71 /// `type_implements_trait` is a convenience function for simple cases like
72 ///
73 /// ```ignore (illustrative)
74 /// let copy_trait = infcx.tcx.require_lang_item(LangItem::Copy, span);
75 /// let implements_copy = infcx.type_implements_trait(copy_trait, [ty], param_env)
76 /// .must_apply_modulo_regions();
77 /// ```
78 ///
79 /// In most cases you should instead create an [Obligation] and check whether
80 /// it holds via [`evaluate_obligation`] or one of its helper functions like
81 /// [`predicate_must_hold_modulo_regions`], because it properly handles higher ranked traits
82 /// and it is more convenient and safer when your `params` are inside a [`Binder`].
83 ///
84 /// [Obligation]: traits::Obligation
85 /// [`evaluate_obligation`]: crate::traits::query::evaluate_obligation::InferCtxtExt::evaluate_obligation
86 /// [`predicate_must_hold_modulo_regions`]: crate::traits::query::evaluate_obligation::InferCtxtExt::predicate_must_hold_modulo_regions
87 /// [`Binder`]: ty::Binder
88#[instrument(level = "debug", skip(self, params), ret)]
89fn type_implements_trait(
90&self,
91 trait_def_id: DefId,
92 params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
93 param_env: ty::ParamEnv<'tcx>,
94 ) -> traits::EvaluationResult {
95let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, params);
9697let obligation = traits::Obligation {
98 cause: traits::ObligationCause::dummy(),
99 param_env,
100 recursion_depth: 0,
101 predicate: trait_ref.upcast(self.tcx),
102 };
103self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
104 }
105106/// Returns `Some` if a type implements a trait shallowly, without side-effects,
107 /// along with any errors that would have been reported upon further obligation
108 /// processing.
109 ///
110 /// - If this returns `Some([])`, then the trait holds modulo regions.
111 /// - If this returns `Some([errors..])`, then the trait has an impl for
112 /// the self type, but some nested obligations do not hold.
113 /// - If this returns `None`, no implementation that applies could be found.
114fn type_implements_trait_shallow(
115&self,
116 trait_def_id: DefId,
117 ty: Ty<'tcx>,
118 param_env: ty::ParamEnv<'tcx>,
119 ) -> Option<TraitErrors<traits::FulfillmentError<'tcx>>> {
120self.probe(|_snapshot| {
121let ocx = ObligationCtxt::new_with_diagnostics(self);
122ocx.register_obligation(Obligation::new(
123self.tcx,
124ObligationCause::dummy(),
125param_env,
126 ty::TraitRef::new(self.tcx, trait_def_id, [ty]),
127 ));
128let errors = ocx.try_evaluate_obligations();
129// Find the original predicate in the list of predicates that could definitely not be fulfilled.
130 // If it is in that list, then we know this doesn't even shallowly implement the trait.
131 // If it is not in that list, it was fulfilled, but there may be nested obligations, which we don't care about here.
132for error in &errors {
133let Some(trait_clause) = error.obligation.predicate.as_trait_clause() else {
134continue;
135 };
136let Some(bound_ty) = trait_clause.self_ty().no_bound_vars() else { continue };
137if trait_clause.def_id() == trait_def_id
138 && ocx.eq(&ObligationCause::dummy(), param_env, bound_ty, ty).is_ok()
139 {
140return None;
141 }
142 }
143Some(errors)
144 })
145 }
146}
147148impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
#[doc = " The \"main method\" for a canonicalized trait query. Given the"]
#[doc = " canonical key `canonical_key`, this method will create a new"]
#[doc = " inference context, instantiate the key, and run your operation"]
#[doc = " `op`. The operation should yield up a result (of type `R`) as"]
#[doc = " well as a set of trait obligations that must be fully"]
#[doc = " satisfied. These obligations will be processed and the"]
#[doc = " canonical result created."]
#[doc = ""]
#[doc = " Returns `NoSolution` in the event of any error."]
#[doc = ""]
#[doc = " (It might be mildly nicer to implement this on `TyCtxt`, and"]
#[doc = " not `InferCtxtBuilder`, but that is a bit tricky right now."]
#[doc = " In part because we would need a `for<\'tcx>` sort of"]
#[doc = " bound for the closure and in part because it is convenient to"]
#[doc =
" have `\'tcx` be free on this function so that we can talk about"]
#[doc = " `K: TypeFoldable<TyCtxt<\'tcx>>`.)"]
fn enter_canonical_trait_query<K,
R>(self, canonical_key: &CanonicalQueryInput<'tcx, K>,
operation:
impl FnOnce(&ObligationCtxt<'_, 'tcx>, K)
-> Result<R, NoSolution>)
-> Result<CanonicalQueryResponse<'tcx, R>, NoSolution> where
K: TypeFoldable<TyCtxt<'tcx>>, R: Debug + TypeFoldable<TyCtxt<'tcx>>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx> {
let (infcx, key, var_values) =
self.build_with_canonical(DUMMY_SP, canonical_key);
let ocx = ObligationCtxt::new(&infcx);
let value = operation(&ocx, key)?;
ocx.make_canonicalized_query_response(var_values, value)
}
}#[extension(pub trait InferCtxtBuilderExt<'tcx>)]149impl<'tcx> InferCtxtBuilder<'tcx> {
150/// The "main method" for a canonicalized trait query. Given the
151 /// canonical key `canonical_key`, this method will create a new
152 /// inference context, instantiate the key, and run your operation
153 /// `op`. The operation should yield up a result (of type `R`) as
154 /// well as a set of trait obligations that must be fully
155 /// satisfied. These obligations will be processed and the
156 /// canonical result created.
157 ///
158 /// Returns `NoSolution` in the event of any error.
159 ///
160 /// (It might be mildly nicer to implement this on `TyCtxt`, and
161 /// not `InferCtxtBuilder`, but that is a bit tricky right now.
162 /// In part because we would need a `for<'tcx>` sort of
163 /// bound for the closure and in part because it is convenient to
164 /// have `'tcx` be free on this function so that we can talk about
165 /// `K: TypeFoldable<TyCtxt<'tcx>>`.)
166fn enter_canonical_trait_query<K, R>(
167self,
168 canonical_key: &CanonicalQueryInput<'tcx, K>,
169 operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
170 ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
171where
172K: TypeFoldable<TyCtxt<'tcx>>,
173 R: Debug + TypeFoldable<TyCtxt<'tcx>>,
174Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
175 {
176let (infcx, key, var_values) = self.build_with_canonical(DUMMY_SP, canonical_key);
177let ocx = ObligationCtxt::new(&infcx);
178let value = operation(&ocx, key)?;
179ocx.make_canonicalized_query_response(var_values, value)
180 }
181}