hir_ty/next_solver/
solver.rs

1//! Defining `SolverContext` for next-trait-solver.
2
3use hir_def::{AssocItemId, GeneralConstId, TypeAliasId};
4use rustc_next_trait_solver::delegate::SolverDelegate;
5use rustc_type_ir::lang_items::SolverTraitLangItem;
6use rustc_type_ir::{
7    InferCtxtLike, Interner, PredicatePolarity, TypeFlags, TypeVisitableExt, UniverseIndex,
8    inherent::{IntoKind, SliceLike, Span as _, Term as _, Ty as _},
9    solve::{Certainty, NoSolution},
10};
11
12use crate::{
13    TraitRefExt,
14    db::HirDatabase,
15    next_solver::{
16        ClauseKind, CoercePredicate, PredicateKind, SubtypePredicate,
17        mapping::{ChalkToNextSolver, convert_args_for_result},
18        util::sizedness_fast_path,
19    },
20};
21
22use super::{
23    Canonical, CanonicalVarValues, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
24    ParamEnv, Predicate, SolverDefId, Span, Ty, UnevaluatedConst,
25    infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt},
26};
27
28pub type Goal<'db, P> = rustc_type_ir::solve::Goal<DbInterner<'db>, P>;
29
30#[repr(transparent)]
31pub(crate) struct SolverContext<'db>(pub(crate) InferCtxt<'db>);
32
33impl<'a, 'db> From<&'a InferCtxt<'db>> for &'a SolverContext<'db> {
34    fn from(infcx: &'a InferCtxt<'db>) -> Self {
35        // SAFETY: `repr(transparent)`
36        unsafe { std::mem::transmute(infcx) }
37    }
38}
39
40impl<'db> std::ops::Deref for SolverContext<'db> {
41    type Target = InferCtxt<'db>;
42
43    fn deref(&self) -> &Self::Target {
44        &self.0
45    }
46}
47
48impl<'db> SolverDelegate for SolverContext<'db> {
49    type Interner = DbInterner<'db>;
50    type Infcx = InferCtxt<'db>;
51
52    fn cx(&self) -> Self::Interner {
53        self.0.interner
54    }
55
56    fn build_with_canonical<V>(
57        cx: Self::Interner,
58        canonical: &rustc_type_ir::CanonicalQueryInput<Self::Interner, V>,
59    ) -> (Self, V, rustc_type_ir::CanonicalVarValues<Self::Interner>)
60    where
61        V: rustc_type_ir::TypeFoldable<Self::Interner>,
62    {
63        let (infcx, value, vars) = cx.infer_ctxt().build_with_canonical(canonical);
64        (SolverContext(infcx), value, vars)
65    }
66
67    fn fresh_var_for_kind_with_span(
68        &self,
69        arg: <Self::Interner as rustc_type_ir::Interner>::GenericArg,
70        span: <Self::Interner as rustc_type_ir::Interner>::Span,
71    ) -> <Self::Interner as rustc_type_ir::Interner>::GenericArg {
72        unimplemented!()
73    }
74
75    fn leak_check(
76        &self,
77        max_input_universe: rustc_type_ir::UniverseIndex,
78    ) -> Result<(), NoSolution> {
79        Ok(())
80    }
81
82    fn well_formed_goals(
83        &self,
84        param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
85        arg: <Self::Interner as rustc_type_ir::Interner>::Term,
86    ) -> Option<
87        Vec<
88            rustc_type_ir::solve::Goal<
89                Self::Interner,
90                <Self::Interner as rustc_type_ir::Interner>::Predicate,
91            >,
92        >,
93    > {
94        unimplemented!()
95    }
96
97    fn make_deduplicated_outlives_constraints(
98        &self,
99    ) -> Vec<
100        rustc_type_ir::OutlivesPredicate<
101            Self::Interner,
102            <Self::Interner as rustc_type_ir::Interner>::GenericArg,
103        >,
104    > {
105        // FIXME: add if we care about regions
106        vec![]
107    }
108
109    fn instantiate_canonical<V>(
110        &self,
111        canonical: rustc_type_ir::Canonical<Self::Interner, V>,
112        values: rustc_type_ir::CanonicalVarValues<Self::Interner>,
113    ) -> V
114    where
115        V: rustc_type_ir::TypeFoldable<Self::Interner>,
116    {
117        canonical.instantiate(self.cx(), &values)
118    }
119
120    fn instantiate_canonical_var_with_infer(
121        &self,
122        cv_info: rustc_type_ir::CanonicalVarKind<Self::Interner>,
123        _span: <Self::Interner as rustc_type_ir::Interner>::Span,
124        universe_map: impl Fn(rustc_type_ir::UniverseIndex) -> rustc_type_ir::UniverseIndex,
125    ) -> <Self::Interner as rustc_type_ir::Interner>::GenericArg {
126        self.0.instantiate_canonical_var(cv_info, universe_map)
127    }
128
129    fn add_item_bounds_for_hidden_type(
130        &self,
131        def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
132        args: <Self::Interner as rustc_type_ir::Interner>::GenericArgs,
133        param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
134        hidden_ty: <Self::Interner as rustc_type_ir::Interner>::Ty,
135        goals: &mut Vec<
136            rustc_type_ir::solve::Goal<
137                Self::Interner,
138                <Self::Interner as rustc_type_ir::Interner>::Predicate,
139            >,
140        >,
141    ) {
142        unimplemented!()
143    }
144
145    fn fetch_eligible_assoc_item(
146        &self,
147        goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
148        trait_assoc_def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
149        impl_def_id: <Self::Interner as rustc_type_ir::Interner>::DefId,
150    ) -> Result<Option<<Self::Interner as rustc_type_ir::Interner>::DefId>, ErrorGuaranteed> {
151        let impl_id = match impl_def_id {
152            SolverDefId::ImplId(id) => id,
153            _ => panic!("Unexpected SolverDefId"),
154        };
155        let trait_assoc_id = match trait_assoc_def_id {
156            SolverDefId::TypeAliasId(id) => id,
157            _ => panic!("Unexpected SolverDefId"),
158        };
159        let trait_ref = self
160            .0
161            .interner
162            .db()
163            .impl_trait(impl_id)
164            // ImplIds for impls where the trait ref can't be resolved should never reach solver
165            .expect("invalid impl passed to next-solver")
166            .into_value_and_skipped_binders()
167            .0;
168        let trait_ = trait_ref.hir_trait_id();
169        let trait_data = trait_.trait_items(self.0.interner.db());
170        let id =
171            impl_id.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> {
172                match item {
173                    (_, AssocItemId::TypeAliasId(type_alias)) => {
174                        let name = &self.0.interner.db().type_alias_signature(*type_alias).name;
175                        let found_trait_assoc_id = trait_data.associated_type_by_name(name)?;
176                        (found_trait_assoc_id == trait_assoc_id).then_some(*type_alias)
177                    }
178                    _ => None,
179                }
180            });
181        Ok(id.map(SolverDefId::TypeAliasId))
182    }
183
184    fn is_transmutable(
185        &self,
186        dst: <Self::Interner as rustc_type_ir::Interner>::Ty,
187        src: <Self::Interner as rustc_type_ir::Interner>::Ty,
188        assume: <Self::Interner as rustc_type_ir::Interner>::Const,
189    ) -> Result<Certainty, NoSolution> {
190        unimplemented!()
191    }
192
193    fn evaluate_const(
194        &self,
195        param_env: <Self::Interner as rustc_type_ir::Interner>::ParamEnv,
196        uv: rustc_type_ir::UnevaluatedConst<Self::Interner>,
197    ) -> Option<<Self::Interner as rustc_type_ir::Interner>::Const> {
198        let c = match uv.def {
199            SolverDefId::ConstId(c) => GeneralConstId::ConstId(c),
200            SolverDefId::StaticId(c) => GeneralConstId::StaticId(c),
201            _ => unreachable!(),
202        };
203        let subst = convert_args_for_result(self.interner, uv.args.as_slice());
204        let ec = self.cx().db.const_eval(c, subst, None).ok()?;
205        Some(ec.to_nextsolver(self.interner))
206    }
207
208    fn compute_goal_fast_path(
209        &self,
210        goal: rustc_type_ir::solve::Goal<
211            Self::Interner,
212            <Self::Interner as rustc_type_ir::Interner>::Predicate,
213        >,
214        span: <Self::Interner as rustc_type_ir::Interner>::Span,
215    ) -> Option<Certainty> {
216        if let Some(trait_pred) = goal.predicate.as_trait_clause() {
217            if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var()
218                // We don't do this fast path when opaques are defined since we may
219                // eventually use opaques to incompletely guide inference via ty var
220                // self types.
221                // FIXME: Properly consider opaques here.
222                && self.inner.borrow_mut().opaque_types().is_empty()
223            {
224                return Some(Certainty::AMBIGUOUS);
225            }
226
227            if trait_pred.polarity() == PredicatePolarity::Positive {
228                match self.0.cx().as_trait_lang_item(trait_pred.def_id()) {
229                    Some(SolverTraitLangItem::Sized) | Some(SolverTraitLangItem::MetaSized) => {
230                        let predicate = self.resolve_vars_if_possible(goal.predicate);
231                        if sizedness_fast_path(self.cx(), predicate, goal.param_env) {
232                            return Some(Certainty::Yes);
233                        }
234                    }
235                    Some(SolverTraitLangItem::Copy | SolverTraitLangItem::Clone) => {
236                        let self_ty =
237                            self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder());
238                        // Unlike `Sized` traits, which always prefer the built-in impl,
239                        // `Copy`/`Clone` may be shadowed by a param-env candidate which
240                        // could force a lifetime error or guide inference. While that's
241                        // not generally desirable, it is observable, so for now let's
242                        // ignore this fast path for types that have regions or infer.
243                        if !self_ty
244                            .has_type_flags(TypeFlags::HAS_FREE_REGIONS | TypeFlags::HAS_INFER)
245                            && self_ty.is_trivially_pure_clone_copy()
246                        {
247                            return Some(Certainty::Yes);
248                        }
249                    }
250                    _ => {}
251                }
252            }
253        }
254
255        let pred = goal.predicate.kind();
256        match pred.no_bound_vars()? {
257            PredicateKind::Clause(ClauseKind::RegionOutlives(outlives)) => Some(Certainty::Yes),
258            PredicateKind::Clause(ClauseKind::TypeOutlives(outlives)) => Some(Certainty::Yes),
259            PredicateKind::Subtype(SubtypePredicate { a, b, .. })
260            | PredicateKind::Coerce(CoercePredicate { a, b }) => {
261                if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() {
262                    // FIXME: We also need to register a subtype relation between these vars
263                    // when those are added, and if they aren't in the same sub root then
264                    // we should mark this goal as `has_changed`.
265                    Some(Certainty::AMBIGUOUS)
266                } else {
267                    None
268                }
269            }
270            PredicateKind::Clause(ClauseKind::ConstArgHasType(ct, _)) => {
271                if self.shallow_resolve_const(ct).is_ct_infer() {
272                    Some(Certainty::AMBIGUOUS)
273                } else {
274                    None
275                }
276            }
277            PredicateKind::Clause(ClauseKind::WellFormed(arg)) => {
278                if arg.is_trivially_wf(self.interner) {
279                    Some(Certainty::Yes)
280                } else if arg.is_infer() {
281                    Some(Certainty::AMBIGUOUS)
282                } else {
283                    None
284                }
285            }
286            _ => None,
287        }
288    }
289}