1use rustc_type_ir::{
29 FnSig, GenericArgKind, 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};
40
41use super::{
42 InferCtxt, InferOk, InferResult, TypeTrace, ValuePairs,
43 traits::{Obligation, ObligationCause},
44};
45
46#[derive(Debug, PartialEq, Eq, Clone, Copy)]
51pub enum DefineOpaqueTypes {
52 Yes,
53 No,
54}
55
56#[derive(Clone, Copy)]
57pub struct At<'a, 'db> {
58 pub infcx: &'a InferCtxt<'db>,
59 pub cause: &'a ObligationCause,
60 pub param_env: ParamEnv<'db>,
61}
62
63impl<'db> InferCtxt<'db> {
64 #[inline]
65 pub fn at<'a>(&'a self, cause: &'a ObligationCause, param_env: ParamEnv<'db>) -> At<'a, 'db> {
66 At { infcx: self, cause, param_env }
67 }
68
69 pub fn fork(&self) -> Self {
73 Self {
74 interner: self.interner,
75 typing_mode: self.typing_mode,
76 inner: self.inner.clone(),
77 tainted_by_errors: self.tainted_by_errors.clone(),
78 universe: self.universe.clone(),
79 }
80 }
81
82 pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<DbInterner<'db>>) -> Self {
86 Self {
90 interner: self.interner,
91 typing_mode,
92 inner: self.inner.clone(),
93 tainted_by_errors: self.tainted_by_errors.clone(),
94 universe: self.universe.clone(),
95 }
96 }
97}
98
99pub trait ToTrace<'db>: Relate<DbInterner<'db>> {
100 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db>;
101}
102
103impl<'a, 'db> At<'a, 'db> {
104 pub fn sup<T>(
109 self,
110 define_opaque_types: DefineOpaqueTypes,
111 expected: T,
112 actual: T,
113 ) -> InferResult<'db, ()>
114 where
115 T: ToTrace<'db>,
116 {
117 RelateExt::relate(
118 self.infcx,
119 self.param_env,
120 expected,
121 Variance::Contravariant,
122 actual,
123 Span::dummy(),
124 )
125 .map(|goals| self.goals_to_obligations(goals))
126 }
127
128 pub fn sub<T>(
130 self,
131 define_opaque_types: DefineOpaqueTypes,
132 expected: T,
133 actual: T,
134 ) -> InferResult<'db, ()>
135 where
136 T: ToTrace<'db>,
137 {
138 RelateExt::relate(
139 self.infcx,
140 self.param_env,
141 expected,
142 Variance::Covariant,
143 actual,
144 Span::dummy(),
145 )
146 .map(|goals| self.goals_to_obligations(goals))
147 }
148
149 pub fn eq<T>(
151 self,
152 define_opaque_types: DefineOpaqueTypes,
153 expected: T,
154 actual: T,
155 ) -> InferResult<'db, ()>
156 where
157 T: ToTrace<'db>,
158 {
159 self.eq_trace(
160 define_opaque_types,
161 ToTrace::to_trace(self.cause, expected, actual),
162 expected,
163 actual,
164 )
165 }
166
167 pub fn eq_trace<T>(
169 self,
170 define_opaque_types: DefineOpaqueTypes,
171 trace: TypeTrace<'db>,
172 expected: T,
173 actual: T,
174 ) -> InferResult<'db, ()>
175 where
176 T: Relate<DbInterner<'db>>,
177 {
178 RelateExt::relate(
179 self.infcx,
180 self.param_env,
181 expected,
182 Variance::Invariant,
183 actual,
184 Span::dummy(),
185 )
186 .map(|goals| self.goals_to_obligations(goals))
187 }
188
189 pub fn relate<T>(
190 self,
191 define_opaque_types: DefineOpaqueTypes,
192 expected: T,
193 variance: Variance,
194 actual: T,
195 ) -> InferResult<'db, ()>
196 where
197 T: ToTrace<'db>,
198 {
199 match variance {
200 Variance::Covariant => self.sub(define_opaque_types, expected, actual),
201 Variance::Invariant => self.eq(define_opaque_types, expected, actual),
202 Variance::Contravariant => self.sup(define_opaque_types, expected, actual),
203
204 Variance::Bivariant => panic!("Bivariant given to `relate()`"),
210 }
211 }
212
213 fn goals_to_obligations(&self, goals: Vec<Goal<'db, Predicate<'db>>>) -> InferOk<'db, ()> {
214 InferOk {
215 value: (),
216 obligations: goals
217 .into_iter()
218 .map(|goal| {
219 Obligation::new(
220 self.infcx.interner,
221 self.cause.clone(),
222 goal.param_env,
223 goal.predicate,
224 )
225 })
226 .collect(),
227 }
228 }
229}
230
231impl<'db> ToTrace<'db> for Ty<'db> {
232 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
233 TypeTrace {
234 cause: cause.clone(),
235 values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
236 }
237 }
238}
239
240impl<'db> ToTrace<'db> for Region<'db> {
241 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
242 TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) }
243 }
244}
245
246impl<'db> ToTrace<'db> for Const<'db> {
247 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
248 TypeTrace {
249 cause: cause.clone(),
250 values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
251 }
252 }
253}
254
255impl<'db> ToTrace<'db> for GenericArg<'db> {
256 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
257 TypeTrace {
258 cause: cause.clone(),
259 values: match (a.kind(), b.kind()) {
260 (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
261 ValuePairs::Regions(ExpectedFound::new(a, b))
262 }
263 (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
264 ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
265 }
266 (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
267 ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
268 }
269 _ => panic!("relating different kinds: {a:?} {b:?}"),
270 },
271 }
272 }
273}
274
275impl<'db> ToTrace<'db> for Term<'db> {
276 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
277 TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) }
278 }
279}
280
281impl<'db> ToTrace<'db> for TraitRef<'db> {
282 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
283 TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
284 }
285}
286
287impl<'db> ToTrace<'db> for AliasTy<'db> {
288 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
289 TypeTrace {
290 cause: cause.clone(),
291 values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())),
292 }
293 }
294}
295
296impl<'db> ToTrace<'db> for AliasTerm<'db> {
297 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
298 TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) }
299 }
300}
301
302impl<'db> ToTrace<'db> for FnSig<DbInterner<'db>> {
303 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
304 TypeTrace {
305 cause: cause.clone(),
306 values: ValuePairs::PolySigs(ExpectedFound::new(Binder::dummy(a), Binder::dummy(b))),
307 }
308 }
309}
310
311impl<'db> ToTrace<'db> for PolyFnSig<'db> {
312 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
313 TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) }
314 }
315}
316
317impl<'db> ToTrace<'db> for PolyExistentialTraitRef<'db> {
318 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
319 TypeTrace {
320 cause: cause.clone(),
321 values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)),
322 }
323 }
324}
325
326impl<'db> ToTrace<'db> for PolyExistentialProjection<'db> {
327 fn to_trace(cause: &ObligationCause, a: Self, b: Self) -> TypeTrace<'db> {
328 TypeTrace {
329 cause: cause.clone(),
330 values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)),
331 }
332 }
333}