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