rustc_trait_selection/solve/
delegate.rs1use std::collections::hash_map::Entry;
2use std::ops::Deref;
3
4use rustc_data_structures::fx::FxHashMap;
5use rustc_hir::LangItem;
6use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
7use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
8use rustc_infer::infer::canonical::{
9 Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues,
10 QueryRegionConstraint,
11};
12use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt};
13use rustc_infer::traits::solve::{FetchEligibleAssocItemResponse, Goal};
14use rustc_middle::traits::query::NoSolution;
15use rustc_middle::traits::solve::Certainty;
16use rustc_middle::ty::{
17 self, MayBeErased, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt, TypingMode,
18};
19use rustc_span::{DUMMY_SP, Span};
20
21use crate::traits::{EvaluateConstErr, ObligationCause, sizedness_fast_path, specialization_graph};
22
23#[repr(transparent)]
24pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
25
26impl<'a, 'tcx> From<&'a InferCtxt<'tcx>> for &'a SolverDelegate<'tcx> {
27 fn from(infcx: &'a InferCtxt<'tcx>) -> Self {
28 unsafe { std::mem::transmute(infcx) }
30 }
31}
32
33impl<'tcx> Deref for SolverDelegate<'tcx> {
34 type Target = InferCtxt<'tcx>;
35
36 fn deref(&self) -> &Self::Target {
37 &self.0
38 }
39}
40
41impl<'tcx> SolverDelegate<'tcx> {
42 fn known_no_opaque_types_in_storage(&self) -> bool {
43 self.inner.borrow_mut().opaque_types().is_empty()
44 && !self.typing_mode_raw().is_erased_not_coherence()
47 }
48}
49
50impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> {
51 type Infcx = InferCtxt<'tcx>;
52 type Interner = TyCtxt<'tcx>;
53
54 fn cx(&self) -> TyCtxt<'tcx> {
55 self.0.tcx
56 }
57
58 fn build_with_canonical<V>(
59 interner: TyCtxt<'tcx>,
60 canonical: &CanonicalQueryInput<'tcx, V>,
61 ) -> (Self, V, CanonicalVarValues<'tcx>)
62 where
63 V: TypeFoldable<TyCtxt<'tcx>>,
64 {
65 let (infcx, value, vars) = interner
66 .infer_ctxt()
67 .with_next_trait_solver(true)
68 .build_with_canonical(DUMMY_SP, canonical);
69 (SolverDelegate(infcx), value, vars)
70 }
71
72 fn compute_goal_fast_path(
73 &self,
74 goal: Goal<'tcx, ty::Predicate<'tcx>>,
75 span: Span,
76 ) -> Option<Certainty> {
77 if self.tcx.assumptions_on_binders() {
79 return None;
80 }
81
82 let pred = goal.predicate.kind();
83 match pred.skip_binder() {
84 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
85 let trait_pred = pred.rebind(trait_pred);
86
87 if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
88 && self.known_no_opaque_types_in_storage()
93 {
94 Some(Certainty::AMBIGUOUS)
95 } else if trait_pred.polarity() == ty::PredicatePolarity::Positive {
96 match self.0.tcx.as_lang_item(trait_pred.def_id()) {
97 Some(LangItem::Sized) | Some(LangItem::MetaSized) => {
98 let predicate = self.resolve_vars_if_possible(goal.predicate);
99 if sizedness_fast_path(self.tcx, predicate, goal.param_env) {
100 return Some(Certainty::Yes);
101 } else {
102 None
103 }
104 }
105 Some(LangItem::Copy | LangItem::Clone) => {
106 let self_ty =
107 self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder());
108 if !self_ty
114 .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER)
115 && self_ty.is_trivially_pure_clone_copy()
116 {
117 return Some(Certainty::Yes);
118 } else {
119 None
120 }
121 }
122 _ => None,
123 }
124 } else {
125 None
126 }
127 }
128 ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
129 Some(Certainty::Yes)
130 }
131 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
132 if outlives.has_escaping_bound_vars() {
133 return None;
134 }
135
136 self.0.sub_regions(
137 SubregionOrigin::RelateRegionParamBound(span, None),
138 outlives.1,
139 outlives.0,
140 ty::VisibleForLeakCheck::Yes,
141 );
142 Some(Certainty::Yes)
143 }
144 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
145 if outlives.has_escaping_bound_vars() {
146 return None;
147 }
148
149 self.0.register_type_outlives_constraint(
150 outlives.0,
151 outlives.1,
152 &ObligationCause::dummy_with_span(span),
153 );
154
155 Some(Certainty::Yes)
156 }
157 ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. })
158 | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
159 if a.has_escaping_bound_vars() || b.has_escaping_bound_vars() {
160 return None;
161 }
162
163 match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) {
164 (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
165 self.sub_unify_ty_vids_raw(a_vid, b_vid);
166 Some(Certainty::AMBIGUOUS)
167 }
168 _ => None,
169 }
170 }
171 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => {
172 if ct.has_escaping_bound_vars() {
173 return None;
174 }
175
176 if self.shallow_resolve_const(ct).is_ct_infer() {
177 Some(Certainty::AMBIGUOUS)
178 } else {
179 None
180 }
181 }
182 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
183 if arg.has_escaping_bound_vars() {
184 return None;
185 }
186
187 let arg = self.shallow_resolve_term(arg);
188 if arg.is_trivially_wf(self.tcx) {
189 Some(Certainty::Yes)
190 } else if arg.is_infer() {
191 Some(Certainty::AMBIGUOUS)
192 } else {
193 None
194 }
195 }
196 _ => None,
197 }
198 }
199
200 fn fresh_var_for_kind_with_span(
201 &self,
202 arg: ty::GenericArg<'tcx>,
203 span: Span,
204 ) -> ty::GenericArg<'tcx> {
205 match arg.kind() {
206 ty::GenericArgKind::Lifetime(_) => {
207 self.next_region_var(RegionVariableOrigin::Misc(span)).into()
208 }
209 ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
210 ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
211 }
212 }
213
214 fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
215 self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
216 }
217
218 fn evaluate_const(
219 &self,
220 param_env: ty::ParamEnv<'tcx>,
221 uv: ty::UnevaluatedConst<'tcx>,
222 ) -> Option<ty::Const<'tcx>> {
223 let ct = ty::Const::new_unevaluated(self.tcx, uv);
224
225 match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
226 Ok(ct) => Some(ct),
227 Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
228 Err(
229 EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
230 ) => None,
231 }
232 }
233
234 fn well_formed_goals(
235 &self,
236 param_env: ty::ParamEnv<'tcx>,
237 term: ty::Term<'tcx>,
238 ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
239 crate::traits::wf::unnormalized_obligations(
240 &self.0,
241 param_env,
242 term,
243 DUMMY_SP,
244 CRATE_DEF_ID,
245 )
246 .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
247 }
248
249 fn make_deduplicated_region_constraints(
250 &self,
251 ) -> Vec<(ty::RegionConstraint<'tcx>, ty::VisibleForLeakCheck)> {
252 let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
255 let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned();
256 let region_constraints = self.0.with_region_constraints(|region_constraints| {
257 make_query_region_constraints(
258 region_obligations,
259 region_constraints,
260 region_assumptions,
261 )
262 });
263
264 let mut seen = FxHashMap::default();
265 let mut constraints = ::alloc::vec::Vec::new()vec![];
266 for QueryRegionConstraint { constraint: outlives, visible_for_leak_check: vis, .. } in
267 region_constraints.constraints
268 {
269 match seen.entry(outlives) {
270 Entry::Occupied(occupied) => {
271 let idx = occupied.get();
272 let (_, prev_vis): &mut (_, ty::VisibleForLeakCheck) =
273 constraints.get_mut(*idx).unwrap();
274 *prev_vis = (*prev_vis).or(vis);
275 }
276 Entry::Vacant(vacant) => {
277 vacant.insert(constraints.len());
278 constraints.push((outlives, vis));
279 }
280 }
281 }
282 constraints
283 }
284
285 fn instantiate_canonical<V>(
286 &self,
287 canonical: Canonical<'tcx, V>,
288 values: CanonicalVarValues<'tcx>,
289 ) -> V
290 where
291 V: TypeFoldable<TyCtxt<'tcx>>,
292 {
293 canonical.instantiate(self.tcx, &values)
294 }
295
296 fn instantiate_canonical_var(
297 &self,
298 kind: CanonicalVarKind<'tcx>,
299 span: Span,
300 var_values: &[ty::GenericArg<'tcx>],
301 universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
302 ) -> ty::GenericArg<'tcx> {
303 self.0.instantiate_canonical_var(span, kind, var_values, universe_map)
304 }
305
306 fn add_item_bounds_for_hidden_type(
307 &self,
308 def_id: DefId,
309 args: ty::GenericArgsRef<'tcx>,
310 param_env: ty::ParamEnv<'tcx>,
311 hidden_ty: Ty<'tcx>,
312 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
313 ) {
314 self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals);
315 }
316
317 fn fetch_eligible_assoc_item(
318 &self,
319 goal_trait_ref: ty::TraitRef<'tcx>,
320 trait_assoc_def_id: DefId,
321 impl_def_id: DefId,
322 ) -> FetchEligibleAssocItemResponse<'tcx> {
323 let node_item =
324 match specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id) {
325 Ok(i) => i,
326 Err(guar) => return FetchEligibleAssocItemResponse::Err(guar),
327 };
328
329 let typing_mode = self.typing_mode_raw();
330
331 let eligible = if node_item.is_final() {
332 true
334 } else {
335 match typing_mode {
340 TypingMode::Coherence
341 | TypingMode::Typeck { .. }
342 | TypingMode::PostTypeckUntilBorrowck { .. }
343 | TypingMode::PostBorrowck { .. } => false,
344 TypingMode::PostAnalysis | TypingMode::Codegen => {
345 let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
346 !poly_trait_ref.still_further_specializable()
347 }
348 TypingMode::ErasedNotCoherence(MayBeErased) => {
349 return FetchEligibleAssocItemResponse::NotFoundBecauseErased;
350 }
351 }
352 };
353
354 if eligible {
356 FetchEligibleAssocItemResponse::Found(node_item.item.def_id)
357 } else {
358 FetchEligibleAssocItemResponse::NotFound(typing_mode.assert_not_erased())
361 }
362 }
363
364 fn is_transmutable(
367 &self,
368 src: Ty<'tcx>,
369 dst: Ty<'tcx>,
370 assume: ty::Const<'tcx>,
371 ) -> Result<Certainty, NoSolution> {
372 let (dst, src) = self.tcx.erase_and_anonymize_regions((dst, src));
375
376 let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else {
377 return Err(NoSolution);
378 };
379
380 match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx).is_transmutable(src, dst, assume) {
382 rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
383 rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
384 }
385 }
386}