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