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