rustc_trait_selection/solve/
delegate.rs
1use std::ops::Deref;
2
3use rustc_data_structures::fx::FxHashSet;
4use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
5use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
6use rustc_infer::infer::canonical::{
7 Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
8};
9use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
10use rustc_infer::traits::ObligationCause;
11use rustc_infer::traits::solve::Goal;
12use rustc_middle::ty::fold::TypeFoldable;
13use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
14use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
15use rustc_type_ir::TypingMode;
16use rustc_type_ir::solve::{Certainty, NoSolution};
17
18use crate::traits::{EvaluateConstErr, specialization_graph};
19
20#[repr(transparent)]
21pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
22
23impl<'a, 'tcx> From<&'a InferCtxt<'tcx>> for &'a SolverDelegate<'tcx> {
24 fn from(infcx: &'a InferCtxt<'tcx>) -> Self {
25 unsafe { std::mem::transmute(infcx) }
27 }
28}
29
30impl<'tcx> Deref for SolverDelegate<'tcx> {
31 type Target = InferCtxt<'tcx>;
32
33 fn deref(&self) -> &Self::Target {
34 &self.0
35 }
36}
37
38impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> {
39 type Infcx = InferCtxt<'tcx>;
40 type Interner = TyCtxt<'tcx>;
41
42 fn cx(&self) -> TyCtxt<'tcx> {
43 self.0.tcx
44 }
45
46 fn build_with_canonical<V>(
47 interner: TyCtxt<'tcx>,
48 canonical: &CanonicalQueryInput<'tcx, V>,
49 ) -> (Self, V, CanonicalVarValues<'tcx>)
50 where
51 V: TypeFoldable<TyCtxt<'tcx>>,
52 {
53 let (infcx, value, vars) = interner
54 .infer_ctxt()
55 .with_next_trait_solver(true)
56 .build_with_canonical(DUMMY_SP, canonical);
57 (SolverDelegate(infcx), value, vars)
58 }
59
60 fn fresh_var_for_kind_with_span(
61 &self,
62 arg: ty::GenericArg<'tcx>,
63 span: Span,
64 ) -> ty::GenericArg<'tcx> {
65 match arg.unpack() {
66 ty::GenericArgKind::Lifetime(_) => {
67 self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into()
68 }
69 ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
70 ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
71 }
72 }
73
74 fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
75 self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
76 }
77
78 fn evaluate_const(
79 &self,
80 param_env: ty::ParamEnv<'tcx>,
81 uv: ty::UnevaluatedConst<'tcx>,
82 ) -> Option<ty::Const<'tcx>> {
83 let ct = ty::Const::new_unevaluated(self.tcx, uv);
84
85 match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
86 Ok(ct) => Some(ct),
87 Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
88 Err(
89 EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
90 ) => None,
91 }
92 }
93
94 fn well_formed_goals(
95 &self,
96 param_env: ty::ParamEnv<'tcx>,
97 arg: ty::GenericArg<'tcx>,
98 ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
99 crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
100 .map(|obligations| {
101 obligations.into_iter().map(|obligation| obligation.into()).collect()
102 })
103 }
104
105 fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
106 self.0.clone_opaque_types_for_query_response()
107 }
108
109 fn make_deduplicated_outlives_constraints(
110 &self,
111 ) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
112 let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
115 let region_constraints = self.0.with_region_constraints(|region_constraints| {
116 make_query_region_constraints(
117 self.tcx,
118 region_obligations
119 .iter()
120 .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
121 region_constraints,
122 )
123 });
124
125 let mut seen = FxHashSet::default();
126 region_constraints
127 .outlives
128 .into_iter()
129 .filter(|&(outlives, _)| seen.insert(outlives))
130 .map(|(outlives, _)| outlives)
131 .collect()
132 }
133
134 fn instantiate_canonical<V>(
135 &self,
136 canonical: Canonical<'tcx, V>,
137 values: CanonicalVarValues<'tcx>,
138 ) -> V
139 where
140 V: TypeFoldable<TyCtxt<'tcx>>,
141 {
142 canonical.instantiate(self.tcx, &values)
143 }
144
145 fn instantiate_canonical_var_with_infer(
146 &self,
147 cv_info: CanonicalVarInfo<'tcx>,
148 span: Span,
149 universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
150 ) -> ty::GenericArg<'tcx> {
151 self.0.instantiate_canonical_var(span, cv_info, universe_map)
152 }
153
154 fn insert_hidden_type(
155 &self,
156 opaque_type_key: ty::OpaqueTypeKey<'tcx>,
157 param_env: ty::ParamEnv<'tcx>,
158 hidden_ty: Ty<'tcx>,
159 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
160 ) -> Result<(), NoSolution> {
161 self.0
162 .insert_hidden_type(opaque_type_key, DUMMY_SP, param_env, hidden_ty, goals)
163 .map_err(|_| NoSolution)
164 }
165
166 fn add_item_bounds_for_hidden_type(
167 &self,
168 def_id: DefId,
169 args: ty::GenericArgsRef<'tcx>,
170 param_env: ty::ParamEnv<'tcx>,
171 hidden_ty: Ty<'tcx>,
172 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
173 ) {
174 self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals);
175 }
176
177 fn inject_new_hidden_type_unchecked(
178 &self,
179 key: ty::OpaqueTypeKey<'tcx>,
180 hidden_ty: Ty<'tcx>,
181 span: Span,
182 ) {
183 self.0.inject_new_hidden_type_unchecked(key, ty::OpaqueHiddenType { ty: hidden_ty, span })
184 }
185
186 fn reset_opaque_types(&self) {
187 let _ = self.take_opaque_types();
188 }
189
190 fn fetch_eligible_assoc_item(
191 &self,
192 goal_trait_ref: ty::TraitRef<'tcx>,
193 trait_assoc_def_id: DefId,
194 impl_def_id: DefId,
195 ) -> Result<Option<DefId>, ErrorGuaranteed> {
196 let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id)?;
197
198 let eligible = if node_item.is_final() {
199 true
201 } else {
202 match self.typing_mode() {
207 TypingMode::Coherence
208 | TypingMode::Analysis { .. }
209 | TypingMode::PostBorrowckAnalysis { .. } => false,
210 TypingMode::PostAnalysis => {
211 let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
212 !poly_trait_ref.still_further_specializable()
213 }
214 }
215 };
216
217 if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) }
219 }
220
221 fn is_transmutable(
224 &self,
225 param_env: ty::ParamEnv<'tcx>,
226 dst: Ty<'tcx>,
227 src: Ty<'tcx>,
228 assume: ty::Const<'tcx>,
229 ) -> Result<Certainty, NoSolution> {
230 let (dst, src) = self.tcx.erase_regions((dst, src));
233
234 let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else {
235 return Err(NoSolution);
236 };
237
238 match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable(
240 ObligationCause::dummy(),
241 rustc_transmute::Types { src, dst },
242 assume,
243 ) {
244 rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
245 rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
246 }
247 }
248}