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