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::Goal;
13use rustc_middle::traits::query::NoSolution;
14use rustc_middle::traits::solve::Certainty;
15use rustc_middle::ty::{
16 self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
17};
18use rustc_span::{DUMMY_SP, ErrorGuaranteed, 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> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<'tcx> {
41 type Infcx = InferCtxt<'tcx>;
42 type Interner = TyCtxt<'tcx>;
43
44 fn cx(&self) -> TyCtxt<'tcx> {
45 self.0.tcx
46 }
47
48 fn build_with_canonical<V>(
49 interner: TyCtxt<'tcx>,
50 canonical: &CanonicalQueryInput<'tcx, V>,
51 ) -> (Self, V, CanonicalVarValues<'tcx>)
52 where
53 V: TypeFoldable<TyCtxt<'tcx>>,
54 {
55 let (infcx, value, vars) = interner
56 .infer_ctxt()
57 .with_next_trait_solver(true)
58 .build_with_canonical(DUMMY_SP, canonical);
59 (SolverDelegate(infcx), value, vars)
60 }
61
62 fn compute_goal_fast_path(
63 &self,
64 goal: Goal<'tcx, ty::Predicate<'tcx>>,
65 span: Span,
66 ) -> Option<Certainty> {
67 if let Some(trait_pred) = goal.predicate.as_trait_clause() {
68 if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
69 && self.inner.borrow_mut().opaque_types().is_empty()
74 {
75 return Some(Certainty::AMBIGUOUS);
76 }
77
78 if trait_pred.polarity() == ty::PredicatePolarity::Positive {
79 match self.0.tcx.as_lang_item(trait_pred.def_id()) {
80 Some(LangItem::Sized) | Some(LangItem::MetaSized) => {
81 let predicate = self.resolve_vars_if_possible(goal.predicate);
82 if sizedness_fast_path(self.tcx, predicate, goal.param_env) {
83 return Some(Certainty::Yes);
84 }
85 }
86 Some(LangItem::Copy | LangItem::Clone) => {
87 let self_ty =
88 self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder());
89 if !self_ty
95 .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER)
96 && self_ty.is_trivially_pure_clone_copy()
97 {
98 return Some(Certainty::Yes);
99 }
100 }
101 _ => {}
102 }
103 }
104 }
105
106 let pred = goal.predicate.kind();
107 match pred.no_bound_vars()? {
108 ty::PredicateKind::DynCompatible(def_id) if self.0.tcx.is_dyn_compatible(def_id) => {
109 Some(Certainty::Yes)
110 }
111 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(outlives)) => {
112 self.0.sub_regions(
113 SubregionOrigin::RelateRegionParamBound(span, None),
114 outlives.1,
115 outlives.0,
116 ty::VisibleForLeakCheck::Yes,
117 );
118 Some(Certainty::Yes)
119 }
120 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
121 self.0.register_type_outlives_constraint(
122 outlives.0,
123 outlives.1,
124 &ObligationCause::dummy_with_span(span),
125 );
126
127 Some(Certainty::Yes)
128 }
129 ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. })
130 | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
131 match (self.shallow_resolve(a).kind(), self.shallow_resolve(b).kind()) {
132 (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
133 self.sub_unify_ty_vids_raw(a_vid, b_vid);
134 Some(Certainty::AMBIGUOUS)
135 }
136 _ => None,
137 }
138 }
139 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) => {
140 if self.shallow_resolve_const(ct).is_ct_infer() {
141 Some(Certainty::AMBIGUOUS)
142 } else {
143 None
144 }
145 }
146 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
147 let arg = self.shallow_resolve_term(arg);
148 if arg.is_trivially_wf(self.tcx) {
149 Some(Certainty::Yes)
150 } else if arg.is_infer() {
151 Some(Certainty::AMBIGUOUS)
152 } else {
153 None
154 }
155 }
156 _ => None,
157 }
158 }
159
160 fn fresh_var_for_kind_with_span(
161 &self,
162 arg: ty::GenericArg<'tcx>,
163 span: Span,
164 ) -> ty::GenericArg<'tcx> {
165 match arg.kind() {
166 ty::GenericArgKind::Lifetime(_) => {
167 self.next_region_var(RegionVariableOrigin::Misc(span)).into()
168 }
169 ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
170 ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
171 }
172 }
173
174 fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
175 self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
176 }
177
178 fn evaluate_const(
179 &self,
180 param_env: ty::ParamEnv<'tcx>,
181 uv: ty::UnevaluatedConst<'tcx>,
182 ) -> Option<ty::Const<'tcx>> {
183 let ct = ty::Const::new_unevaluated(self.tcx, uv);
184
185 match crate::traits::try_evaluate_const(&self.0, ct, param_env) {
186 Ok(ct) => Some(ct),
187 Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
188 Err(
189 EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
190 ) => None,
191 }
192 }
193
194 fn well_formed_goals(
195 &self,
196 param_env: ty::ParamEnv<'tcx>,
197 term: ty::Term<'tcx>,
198 ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
199 crate::traits::wf::unnormalized_obligations(
200 &self.0,
201 param_env,
202 term,
203 DUMMY_SP,
204 CRATE_DEF_ID,
205 )
206 .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
207 }
208
209 fn make_deduplicated_region_constraints(
210 &self,
211 ) -> Vec<(ty::RegionConstraint<'tcx>, ty::VisibleForLeakCheck)> {
212 let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
215 let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned();
216 let region_constraints = self.0.with_region_constraints(|region_constraints| {
217 make_query_region_constraints(
218 region_obligations,
219 region_constraints,
220 region_assumptions,
221 )
222 });
223
224 let mut seen = FxHashMap::default();
225 let mut constraints = ::alloc::vec::Vec::new()vec![];
226 for (outlives, _, vis) in region_constraints.constraints {
227 match seen.entry(outlives) {
228 Entry::Occupied(occupied) => {
229 let idx = occupied.get();
230 let (_, prev_vis): &mut (_, ty::VisibleForLeakCheck) =
231 constraints.get_mut(*idx).unwrap();
232 *prev_vis = (*prev_vis).or(vis);
233 }
234 Entry::Vacant(vacant) => {
235 vacant.insert(constraints.len());
236 constraints.push((outlives, vis));
237 }
238 }
239 }
240 constraints
241 }
242
243 fn instantiate_canonical<V>(
244 &self,
245 canonical: Canonical<'tcx, V>,
246 values: CanonicalVarValues<'tcx>,
247 ) -> V
248 where
249 V: TypeFoldable<TyCtxt<'tcx>>,
250 {
251 canonical.instantiate(self.tcx, &values)
252 }
253
254 fn instantiate_canonical_var(
255 &self,
256 kind: CanonicalVarKind<'tcx>,
257 span: Span,
258 var_values: &[ty::GenericArg<'tcx>],
259 universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
260 ) -> ty::GenericArg<'tcx> {
261 self.0.instantiate_canonical_var(span, kind, var_values, universe_map)
262 }
263
264 fn add_item_bounds_for_hidden_type(
265 &self,
266 def_id: DefId,
267 args: ty::GenericArgsRef<'tcx>,
268 param_env: ty::ParamEnv<'tcx>,
269 hidden_ty: Ty<'tcx>,
270 goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
271 ) {
272 self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals);
273 }
274
275 fn fetch_eligible_assoc_item(
276 &self,
277 goal_trait_ref: ty::TraitRef<'tcx>,
278 trait_assoc_def_id: DefId,
279 impl_def_id: DefId,
280 ) -> Result<Option<DefId>, ErrorGuaranteed> {
281 let node_item = specialization_graph::assoc_def(self.tcx, impl_def_id, trait_assoc_def_id)?;
282
283 let eligible = if node_item.is_final() {
284 true
286 } else {
287 match self.typing_mode() {
292 TypingMode::Coherence
293 | TypingMode::Analysis { .. }
294 | TypingMode::Borrowck { .. }
295 | TypingMode::PostBorrowckAnalysis { .. } => false,
296 TypingMode::PostAnalysis => {
297 let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
298 !poly_trait_ref.still_further_specializable()
299 }
300 }
301 };
302
303 if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) }
305 }
306
307 fn is_transmutable(
310 &self,
311 src: Ty<'tcx>,
312 dst: Ty<'tcx>,
313 assume: ty::Const<'tcx>,
314 ) -> Result<Certainty, NoSolution> {
315 let (dst, src) = self.tcx.erase_and_anonymize_regions((dst, src));
318
319 let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else {
320 return Err(NoSolution);
321 };
322
323 match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx).is_transmutable(src, dst, assume) {
325 rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
326 rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
327 }
328 }
329}