1use rustc_type_ir::{
29 FnSig, GenericArgKind, TypeFoldable, TypingMode, Variance,
30 error::ExpectedFound,
31 inherent::{IntoKind, Span as _},
32 relate::{Relate, TypeRelation, solver_relating::RelateExt},
33};
34
35use crate::next_solver::{
36 AliasTerm, AliasTy, Binder, Const, DbInterner, GenericArg, Goal, ParamEnv,
37 PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, Predicate, Region, Span, Term,
38 TraitRef, Ty,
39 fulfill::NextSolverError,
40 infer::relate::lattice::{LatticeOp, LatticeOpKind},
41};
42
43use super::{
44 InferCtxt, InferOk, InferResult, TypeTrace, ValuePairs,
45 traits::{Obligation, ObligationCause},
46};
47
48#[derive(Clone, Copy)]
49pub struct At<'a, 'db> {
50 pub infcx: &'a InferCtxt<'db>,
51 pub cause: &'a ObligationCause,
52 pub param_env: ParamEnv<'db>,
53}
54
55impl<'db> InferCtxt<'db> {
56 #[inline]
57 pub fn at<'a>(&'a self, cause: &'a ObligationCause, param_env: ParamEnv<'db>) -> At<'a, 'db> {
58 At { infcx: self, cause, param_env }
59 }
60
61 pub fn fork(&self) -> Self {
65 Self {
66 interner: self.interner,
67 typing_mode: self.typing_mode,
68 inner: self.inner.clone(),
69 tainted_by_errors: self.tainted_by_errors.clone(),
70 universe: self.universe.clone(),
71 }
72 }
73
74 pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<DbInterner<'db>>) -> Self {
78 Self {
82 interner: self.interner,
83 typing_mode,
84 inner: self.inner.clone(),
85 tainted_by_errors: self.tainted_by_errors.clone(),
86 universe: self.universe.clone(),
87 }
88 }
89}
90
91pub trait ToTrace<'db>: Relate<DbInterner<'db>> {
92 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db>;
93}
94
95impl<'a, 'db> At<'a, 'db> {
96 pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
101 where
102 T: ToTrace<'db>,
103 {
104 RelateExt::relate(
105 self.infcx,
106 self.param_env,
107 expected,
108 Variance::Contravariant,
109 actual,
110 Span::dummy(),
111 )
112 .map(|goals| self.goals_to_obligations(goals))
113 }
114
115 pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
117 where
118 T: ToTrace<'db>,
119 {
120 RelateExt::relate(
121 self.infcx,
122 self.param_env,
123 expected,
124 Variance::Covariant,
125 actual,
126 Span::dummy(),
127 )
128 .map(|goals| self.goals_to_obligations(goals))
129 }
130
131 pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'db, ()>
133 where
134 T: Relate<DbInterner<'db>>,
135 {
136 RelateExt::relate(
137 self.infcx,
138 self.param_env,
139 expected,
140 Variance::Invariant,
141 actual,
142 Span::dummy(),
143 )
144 .map(|goals| self.goals_to_obligations(goals))
145 }
146
147 pub fn relate<T>(self, expected: T, variance: Variance, actual: T) -> InferResult<'db, ()>
148 where
149 T: ToTrace<'db>,
150 {
151 match variance {
152 Variance::Covariant => self.sub(expected, actual),
153 Variance::Invariant => self.eq(expected, actual),
154 Variance::Contravariant => self.sup(expected, actual),
155
156 Variance::Bivariant => panic!("Bivariant given to `relate()`"),
162 }
163 }
164
165 pub fn deeply_normalize<T>(self, value: T) -> Result<T, Vec<NextSolverError<'db>>>
168 where
169 T: TypeFoldable<DbInterner<'db>>,
170 {
171 crate::next_solver::normalize::deeply_normalize(self, value)
172 }
173
174 pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'db, T>
180 where
181 T: ToTrace<'db>,
182 {
183 let mut op = LatticeOp::new(
184 self.infcx,
185 ToTrace::to_trace(self.cause, expected, actual),
186 self.param_env,
187 LatticeOpKind::Lub,
188 );
189 let value = op.relate(expected, actual)?;
190 Ok(InferOk { value, obligations: op.into_obligations() })
191 }
192
193 fn goals_to_obligations(&self, goals: Vec<Goal<'db, Predicate<'db>>>) -> InferOk<'db, ()> {
194 InferOk {
195 value: (),
196 obligations: goals
197 .into_iter()
198 .map(|goal| {
199 Obligation::new(
200 self.infcx.interner,
201 self.cause.clone(),
202 goal.param_env,
203 goal.predicate,
204 )
205 })
206 .collect(),
207 }
208 }
209}
210
211impl<'db> ToTrace<'db> for Ty<'db> {
212 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
213 TypeTrace {
214 cause: cause.clone(),
215 values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
216 }
217 }
218}
219
220impl<'db> ToTrace<'db> for Region<'db> {
221 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
222 TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) }
223 }
224}
225
226impl<'db> ToTrace<'db> for Const<'db> {
227 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
228 TypeTrace {
229 cause: cause.clone(),
230 values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
231 }
232 }
233}
234
235impl<'db> ToTrace<'db> for GenericArg<'db> {
236 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
237 TypeTrace {
238 cause: cause.clone(),
239 values: match (a.kind(), b.kind()) {
240 (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
241 ValuePairs::Regions(ExpectedFound::new(a, b))
242 }
243 (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
244 ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
245 }
246 (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
247 ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
248 }
249 _ => panic!("relating different kinds: {a:?} {b:?}"),
250 },
251 }
252 }
253}
254
255impl<'db> ToTrace<'db> for Term<'db> {
256 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
257 TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) }
258 }
259}
260
261impl<'db> ToTrace<'db> for TraitRef<'db> {
262 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
263 TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
264 }
265}
266
267impl<'db> ToTrace<'db> for AliasTy<'db> {
268 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
269 TypeTrace {
270 cause: cause.clone(),
271 values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())),
272 }
273 }
274}
275
276impl<'db> ToTrace<'db> for AliasTerm<'db> {
277 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
278 TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) }
279 }
280}
281
282impl<'db> ToTrace<'db> for FnSig<DbInterner<'db>> {
283 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
284 TypeTrace {
285 cause: cause.clone(),
286 values: ValuePairs::PolySigs(ExpectedFound::new(Binder::dummy(a), Binder::dummy(b))),
287 }
288 }
289}
290
291impl<'db> ToTrace<'db> for PolyFnSig<'db> {
292 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
293 TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) }
294 }
295}
296
297impl<'db> ToTrace<'db> for PolyExistentialTraitRef<'db> {
298 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
299 TypeTrace {
300 cause: cause.clone(),
301 values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)),
302 }
303 }
304}
305
306impl<'db> ToTrace<'db> for PolyExistentialProjection<'db> {
307 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
308 TypeTrace {
309 cause: cause.clone(),
310 values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)),
311 }
312 }
313}