1use hir_def::{AssocItemId, GeneralConstId};
4use rustc_next_trait_solver::delegate::SolverDelegate;
5use rustc_type_ir::{
6 AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags,
7 TypeVisitableExt,
8 inherent::{IntoKind, SliceLike, Term as _, Ty as _},
9 lang_items::SolverTraitLangItem,
10 solve::{Certainty, NoSolution},
11};
12use tracing::debug;
13
14use crate::next_solver::{
15 AliasTy, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs, ImplIdWrapper,
16 ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, fold::fold_tys,
17 util::sizedness_fast_path,
18};
19
20use super::{
21 DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span,
22 infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt},
23};
24
25pub type Goal<'db, P> = rustc_type_ir::solve::Goal<DbInterner<'db>, P>;
26
27#[repr(transparent)]
28pub(crate) struct SolverContext<'db>(pub(crate) InferCtxt<'db>);
29
30impl<'a, 'db> From<&'a InferCtxt<'db>> for &'a SolverContext<'db> {
31 fn from(infcx: &'a InferCtxt<'db>) -> Self {
32 unsafe { std::mem::transmute(infcx) }
34 }
35}
36
37impl<'db> std::ops::Deref for SolverContext<'db> {
38 type Target = InferCtxt<'db>;
39
40 fn deref(&self) -> &Self::Target {
41 &self.0
42 }
43}
44
45impl<'db> SolverDelegate for SolverContext<'db> {
46 type Interner = DbInterner<'db>;
47 type Infcx = InferCtxt<'db>;
48
49 fn cx(&self) -> Self::Interner {
50 self.0.interner
51 }
52
53 fn build_with_canonical<V>(
54 cx: Self::Interner,
55 canonical: &rustc_type_ir::CanonicalQueryInput<Self::Interner, V>,
56 ) -> (Self, V, rustc_type_ir::CanonicalVarValues<Self::Interner>)
57 where
58 V: rustc_type_ir::TypeFoldable<Self::Interner>,
59 {
60 let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(canonical);
61 (SolverContext(infcx), value, vars)
62 }
63
64 fn fresh_var_for_kind_with_span(&self, arg: GenericArg<'db>, _span: Span) -> GenericArg<'db> {
65 match arg.kind() {
66 GenericArgKind::Lifetime(_) => self.next_region_var().into(),
67 GenericArgKind::Type(_) => self.next_ty_var().into(),
68 GenericArgKind::Const(_) => self.next_const_var().into(),
69 }
70 }
71
72 fn leak_check(
73 &self,
74 _max_input_universe: rustc_type_ir::UniverseIndex,
75 ) -> Result<(), NoSolution> {
76 Ok(())
77 }
78
79 fn well_formed_goals(
80 &self,
81 _param_env: ParamEnv<'db>,
82 _arg: <Self::Interner as rustc_type_ir::Interner>::Term,
83 ) -> Option<
84 Vec<
85 rustc_type_ir::solve::Goal<
86 Self::Interner,
87 <Self::Interner as rustc_type_ir::Interner>::Predicate,
88 >,
89 >,
90 > {
91 None
93 }
94
95 fn make_deduplicated_outlives_constraints(
96 &self,
97 ) -> Vec<
98 rustc_type_ir::OutlivesPredicate<
99 Self::Interner,
100 <Self::Interner as rustc_type_ir::Interner>::GenericArg,
101 >,
102 > {
103 vec![]
105 }
106
107 fn instantiate_canonical<V>(
108 &self,
109 canonical: rustc_type_ir::Canonical<Self::Interner, V>,
110 values: rustc_type_ir::CanonicalVarValues<Self::Interner>,
111 ) -> V
112 where
113 V: rustc_type_ir::TypeFoldable<Self::Interner>,
114 {
115 canonical.instantiate(self.cx(), &values)
116 }
117
118 fn instantiate_canonical_var(
119 &self,
120 kind: CanonicalVarKind<'db>,
121 _span: <Self::Interner as Interner>::Span,
122 var_values: &[GenericArg<'db>],
123 universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex,
124 ) -> GenericArg<'db> {
125 self.0.instantiate_canonical_var(kind, var_values, universe_map)
126 }
127
128 fn add_item_bounds_for_hidden_type(
129 &self,
130 def_id: SolverDefId,
131 args: GenericArgs<'db>,
132 param_env: ParamEnv<'db>,
133 hidden_ty: Ty<'db>,
134 goals: &mut Vec<Goal<'db, Predicate<'db>>>,
135 ) {
136 let interner = self.interner;
137 let opaque_id = def_id.expect_opaque_ty();
138 goals.push(Goal::new(interner, param_env, ClauseKind::WellFormed(hidden_ty.into())));
150
151 let replace_opaques_in = |clause: Clause<'db>| {
152 fold_tys(interner, clause, |ty| match ty.kind() {
153 TyKind::Alias(
156 AliasTyKind::Opaque,
157 AliasTy { def_id: def_id2, args: args2, .. },
158 ) if def_id == def_id2 && args == args2 => hidden_ty,
159 _ => ty,
160 })
161 };
162
163 let item_bounds = opaque_id.predicates(interner.db);
164 for predicate in item_bounds.iter_instantiated_copied(interner, args.as_slice()) {
165 let predicate = replace_opaques_in(predicate);
166
167 debug!(?predicate);
169 goals.push(Goal::new(interner, param_env, predicate));
170 }
171 }
172
173 fn fetch_eligible_assoc_item(
174 &self,
175 _goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
176 trait_assoc_def_id: SolverDefId,
177 impl_id: ImplIdWrapper,
178 ) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
179 let impl_items = impl_id.0.impl_items(self.0.interner.db());
180 let id =
181 match trait_assoc_def_id {
182 SolverDefId::TypeAliasId(trait_assoc_id) => {
183 let trait_assoc_data = self.0.interner.db.type_alias_signature(trait_assoc_id);
184 impl_items
185 .items
186 .iter()
187 .find_map(|(impl_assoc_name, impl_assoc_id)| {
188 if let AssocItemId::TypeAliasId(impl_assoc_id) = *impl_assoc_id
189 && *impl_assoc_name == trait_assoc_data.name
190 {
191 Some(impl_assoc_id)
192 } else {
193 None
194 }
195 })
196 .or_else(|| {
197 if trait_assoc_data.ty.is_some() { Some(trait_assoc_id) } else { None }
198 })
199 .map(SolverDefId::TypeAliasId)
200 }
201 SolverDefId::ConstId(trait_assoc_id) => {
202 let trait_assoc_data = self.0.interner.db.const_signature(trait_assoc_id);
203 let trait_assoc_name = trait_assoc_data
204 .name
205 .as_ref()
206 .expect("unnamed consts should not get passed to the solver");
207 impl_items
208 .items
209 .iter()
210 .find_map(|(impl_assoc_name, impl_assoc_id)| {
211 if let AssocItemId::ConstId(impl_assoc_id) = *impl_assoc_id
212 && impl_assoc_name == trait_assoc_name
213 {
214 Some(impl_assoc_id)
215 } else {
216 None
217 }
218 })
219 .or_else(|| {
220 if trait_assoc_data.has_body() { Some(trait_assoc_id) } else { None }
221 })
222 .map(SolverDefId::ConstId)
223 }
224 _ => panic!("Unexpected SolverDefId"),
225 };
226 Ok(id)
227 }
228
229 fn is_transmutable(
230 &self,
231 _dst: Ty<'db>,
232 _src: Ty<'db>,
233 _assume: <Self::Interner as rustc_type_ir::Interner>::Const,
234 ) -> Result<Certainty, NoSolution> {
235 Ok(Certainty::Yes)
238 }
239
240 fn evaluate_const(
241 &self,
242 _param_env: ParamEnv<'db>,
243 uv: rustc_type_ir::UnevaluatedConst<Self::Interner>,
244 ) -> Option<<Self::Interner as rustc_type_ir::Interner>::Const> {
245 match uv.def.0 {
246 GeneralConstId::ConstId(c) => {
247 let subst = uv.args;
248 let ec = self.cx().db.const_eval(c, subst, None).ok()?;
249 Some(ec)
250 }
251 GeneralConstId::StaticId(c) => {
252 let ec = self.cx().db.const_eval_static(c).ok()?;
253 Some(ec)
254 }
255 }
256 }
257
258 fn compute_goal_fast_path(
259 &self,
260 goal: rustc_type_ir::solve::Goal<
261 Self::Interner,
262 <Self::Interner as rustc_type_ir::Interner>::Predicate,
263 >,
264 _span: <Self::Interner as rustc_type_ir::Interner>::Span,
265 ) -> Option<Certainty> {
266 if let Some(trait_pred) = goal.predicate.as_trait_clause() {
267 if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
268 && self.inner.borrow_mut().opaque_types().is_empty()
273 {
274 return Some(Certainty::AMBIGUOUS);
275 }
276
277 if trait_pred.polarity() == PredicatePolarity::Positive {
278 match self.0.cx().as_trait_lang_item(trait_pred.def_id()) {
279 Some(SolverTraitLangItem::Sized) | Some(SolverTraitLangItem::MetaSized) => {
280 let predicate = self.resolve_vars_if_possible(goal.predicate);
281 if sizedness_fast_path(self.cx(), predicate, goal.param_env) {
282 return Some(Certainty::Yes);
283 }
284 }
285 Some(SolverTraitLangItem::Copy | SolverTraitLangItem::Clone) => {
286 let self_ty =
287 self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder());
288 if !self_ty
294 .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER)
295 && self_ty.is_trivially_pure_clone_copy()
296 {
297 return Some(Certainty::Yes);
298 }
299 }
300 _ => {}
301 }
302 }
303 }
304
305 let pred = goal.predicate.kind();
306 match pred.no_bound_vars()? {
307 PredicateKind::Clause(ClauseKind::RegionOutlives(_outlives)) => Some(Certainty::Yes),
308 PredicateKind::Clause(ClauseKind::TypeOutlives(_outlives)) => Some(Certainty::Yes),
309 PredicateKind::Subtype(SubtypePredicate { a, b, .. })
310 | PredicateKind::Coerce(CoercePredicate { a, b }) => {
311 if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
312 Some(Certainty::AMBIGUOUS)
316 } else {
317 None
318 }
319 }
320 PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, _)) => {
321 if self.shallow_resolve_const(ct).is_ct_infer() {
322 Some(Certainty::AMBIGUOUS)
323 } else {
324 None
325 }
326 }
327 PredicateKind::Clause(ClauseKind::WellFormed(arg)) => {
328 if arg.is_trivially_wf(self.interner) {
329 Some(Certainty::Yes)
330 } else if arg.is_infer() {
331 Some(Certainty::AMBIGUOUS)
332 } else {
333 None
334 }
335 }
336 _ => None,
337 }
338 }
339}