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