rustc_infer/infer/
at.rs

1//! A nice interface for working with the infcx. The basic idea is to
2//! do `infcx.at(cause, param_env)`, which sets the "cause" of the
3//! operation as well as the surrounding parameter environment. Then
4//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a
5//! subtype or equality relationship respectively. The first argument
6//! is always the "expected" output from the POV of diagnostics.
7//!
8//! Examples:
9//! ```ignore (fragment)
10//!     infcx.at(cause, param_env).sub(a, b)
11//!     // requires that `a <: b`, with `a` considered the "expected" type
12//!
13//!     infcx.at(cause, param_env).sup(a, b)
14//!     // requires that `b <: a`, with `a` considered the "expected" type
15//!
16//!     infcx.at(cause, param_env).eq(a, b)
17//!     // requires that `a == b`, with `a` considered the "expected" type
18//! ```
19//! For finer-grained control, you can also do use `trace`:
20//! ```ignore (fragment)
21//!     infcx.at(...).trace(a, b).sub(&c, &d)
22//! ```
23//! This will set `a` and `b` as the "root" values for
24//! error-reporting, but actually operate on `c` and `d`. This is
25//! sometimes useful when the types of `c` and `d` are not traceable
26//! things. (That system should probably be refactored.)
27
28use relate::lattice::{LatticeOp, LatticeOpKind};
29use rustc_middle::bug;
30use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate;
31use rustc_middle::ty::{Const, ImplSubject, TypingMode};
32
33use super::*;
34use crate::infer::relate::type_relating::TypeRelating;
35use crate::infer::relate::{Relate, TypeRelation};
36use crate::traits::Obligation;
37use crate::traits::solve::Goal;
38
39/// Whether we should define opaque types or just treat them opaquely.
40///
41/// Currently only used to prevent predicate matching from matching anything
42/// against opaque types.
43#[derive(Debug, PartialEq, Eq, Clone, Copy)]
44pub enum DefineOpaqueTypes {
45    Yes,
46    No,
47}
48
49#[derive(Clone, Copy)]
50pub struct At<'a, 'tcx> {
51    pub infcx: &'a InferCtxt<'tcx>,
52    pub cause: &'a ObligationCause<'tcx>,
53    pub param_env: ty::ParamEnv<'tcx>,
54}
55
56impl<'tcx> InferCtxt<'tcx> {
57    #[inline]
58    pub fn at<'a>(
59        &'a self,
60        cause: &'a ObligationCause<'tcx>,
61        param_env: ty::ParamEnv<'tcx>,
62    ) -> At<'a, 'tcx> {
63        At { infcx: self, cause, param_env }
64    }
65
66    /// Forks the inference context, creating a new inference context with the same inference
67    /// variables in the same state. This can be used to "branch off" many tests from the same
68    /// common state.
69    pub fn fork(&self) -> Self {
70        Self {
71            tcx: self.tcx,
72            typing_mode: self.typing_mode,
73            considering_regions: self.considering_regions,
74            skip_leak_check: self.skip_leak_check,
75            inner: self.inner.clone(),
76            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
77            selection_cache: self.selection_cache.clone(),
78            evaluation_cache: self.evaluation_cache.clone(),
79            reported_trait_errors: self.reported_trait_errors.clone(),
80            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
81            tainted_by_errors: self.tainted_by_errors.clone(),
82            universe: self.universe.clone(),
83            next_trait_solver: self.next_trait_solver,
84            obligation_inspector: self.obligation_inspector.clone(),
85        }
86    }
87
88    /// Forks the inference context, creating a new inference context with the same inference
89    /// variables in the same state, except possibly changing the intercrate mode. This can be
90    /// used to "branch off" many tests from the same common state. Used in negative coherence.
91    pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self {
92        // Unlike `fork`, this invalidates all cache entries as they may depend on the
93        // typing mode.
94        let forked = Self {
95            tcx: self.tcx,
96            typing_mode,
97            considering_regions: self.considering_regions,
98            skip_leak_check: self.skip_leak_check,
99            inner: self.inner.clone(),
100            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
101            selection_cache: Default::default(),
102            evaluation_cache: Default::default(),
103            reported_trait_errors: self.reported_trait_errors.clone(),
104            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
105            tainted_by_errors: self.tainted_by_errors.clone(),
106            universe: self.universe.clone(),
107            next_trait_solver: self.next_trait_solver,
108            obligation_inspector: self.obligation_inspector.clone(),
109        };
110        forked.inner.borrow_mut().projection_cache().clear();
111        forked
112    }
113}
114
115pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
116    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>;
117}
118
119impl<'a, 'tcx> At<'a, 'tcx> {
120    /// Makes `actual <: expected`. For example, if type-checking a
121    /// call like `foo(x)`, where `foo: fn(i32)`, you might have
122    /// `sup(i32, x)`, since the "expected" type is the type that
123    /// appears in the signature.
124    pub fn sup<T>(
125        self,
126        define_opaque_types: DefineOpaqueTypes,
127        expected: T,
128        actual: T,
129    ) -> InferResult<'tcx, ()>
130    where
131        T: ToTrace<'tcx>,
132    {
133        if self.infcx.next_trait_solver {
134            NextSolverRelate::relate(
135                self.infcx,
136                self.param_env,
137                expected,
138                ty::Contravariant,
139                actual,
140                self.cause.span,
141            )
142            .map(|goals| self.goals_to_obligations(goals))
143        } else {
144            let mut op = TypeRelating::new(
145                self.infcx,
146                ToTrace::to_trace(self.cause, expected, actual),
147                self.param_env,
148                define_opaque_types,
149                ty::Contravariant,
150            );
151            op.relate(expected, actual)?;
152            Ok(InferOk { value: (), obligations: op.into_obligations() })
153        }
154    }
155
156    /// Makes `expected <: actual`.
157    pub fn sub<T>(
158        self,
159        define_opaque_types: DefineOpaqueTypes,
160        expected: T,
161        actual: T,
162    ) -> InferResult<'tcx, ()>
163    where
164        T: ToTrace<'tcx>,
165    {
166        if self.infcx.next_trait_solver {
167            NextSolverRelate::relate(
168                self.infcx,
169                self.param_env,
170                expected,
171                ty::Covariant,
172                actual,
173                self.cause.span,
174            )
175            .map(|goals| self.goals_to_obligations(goals))
176        } else {
177            let mut op = TypeRelating::new(
178                self.infcx,
179                ToTrace::to_trace(self.cause, expected, actual),
180                self.param_env,
181                define_opaque_types,
182                ty::Covariant,
183            );
184            op.relate(expected, actual)?;
185            Ok(InferOk { value: (), obligations: op.into_obligations() })
186        }
187    }
188
189    /// Makes `expected == actual`.
190    pub fn eq<T>(
191        self,
192        define_opaque_types: DefineOpaqueTypes,
193        expected: T,
194        actual: T,
195    ) -> InferResult<'tcx, ()>
196    where
197        T: ToTrace<'tcx>,
198    {
199        self.eq_trace(
200            define_opaque_types,
201            ToTrace::to_trace(self.cause, expected, actual),
202            expected,
203            actual,
204        )
205    }
206
207    /// Makes `expected == actual`.
208    pub fn eq_trace<T>(
209        self,
210        define_opaque_types: DefineOpaqueTypes,
211        trace: TypeTrace<'tcx>,
212        expected: T,
213        actual: T,
214    ) -> InferResult<'tcx, ()>
215    where
216        T: Relate<TyCtxt<'tcx>>,
217    {
218        if self.infcx.next_trait_solver {
219            NextSolverRelate::relate(
220                self.infcx,
221                self.param_env,
222                expected,
223                ty::Invariant,
224                actual,
225                self.cause.span,
226            )
227            .map(|goals| self.goals_to_obligations(goals))
228        } else {
229            let mut op = TypeRelating::new(
230                self.infcx,
231                trace,
232                self.param_env,
233                define_opaque_types,
234                ty::Invariant,
235            );
236            op.relate(expected, actual)?;
237            Ok(InferOk { value: (), obligations: op.into_obligations() })
238        }
239    }
240
241    pub fn relate<T>(
242        self,
243        define_opaque_types: DefineOpaqueTypes,
244        expected: T,
245        variance: ty::Variance,
246        actual: T,
247    ) -> InferResult<'tcx, ()>
248    where
249        T: ToTrace<'tcx>,
250    {
251        match variance {
252            ty::Covariant => self.sub(define_opaque_types, expected, actual),
253            ty::Invariant => self.eq(define_opaque_types, expected, actual),
254            ty::Contravariant => self.sup(define_opaque_types, expected, actual),
255
256            // We could make this make sense but it's not readily
257            // exposed and I don't feel like dealing with it. Note
258            // that bivariance in general does a bit more than just
259            // *nothing*, it checks that the types are the same
260            // "modulo variance" basically.
261            ty::Bivariant => panic!("Bivariant given to `relate()`"),
262        }
263    }
264
265    /// Computes the least-upper-bound, or mutual supertype, of two
266    /// values. The order of the arguments doesn't matter, but since
267    /// this can result in an error (e.g., if asked to compute LUB of
268    /// u32 and i32), it is meaningful to call one of them the
269    /// "expected type".
270    pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
271    where
272        T: ToTrace<'tcx>,
273    {
274        let mut op = LatticeOp::new(
275            self.infcx,
276            ToTrace::to_trace(self.cause, expected, actual),
277            self.param_env,
278            LatticeOpKind::Lub,
279        );
280        let value = op.relate(expected, actual)?;
281        Ok(InferOk { value, obligations: op.into_obligations() })
282    }
283
284    fn goals_to_obligations(
285        &self,
286        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
287    ) -> InferOk<'tcx, ()> {
288        InferOk {
289            value: (),
290            obligations: goals
291                .into_iter()
292                .map(|goal| {
293                    Obligation::new(
294                        self.infcx.tcx,
295                        self.cause.clone(),
296                        goal.param_env,
297                        goal.predicate,
298                    )
299                })
300                .collect(),
301        }
302    }
303}
304
305impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
306    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
307        match (a, b) {
308            (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
309                ToTrace::to_trace(cause, trait_ref_a, trait_ref_b)
310            }
311            (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
312                ToTrace::to_trace(cause, ty_a, ty_b)
313            }
314            (ImplSubject::Trait(_), ImplSubject::Inherent(_))
315            | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
316                bug!("can not trace TraitRef and Ty");
317            }
318        }
319    }
320}
321
322impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
323    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
324        TypeTrace {
325            cause: cause.clone(),
326            values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
327        }
328    }
329}
330
331impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
332    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
333        TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) }
334    }
335}
336
337impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
338    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
339        TypeTrace {
340            cause: cause.clone(),
341            values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
342        }
343    }
344}
345
346impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
347    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
348        TypeTrace {
349            cause: cause.clone(),
350            values: match (a.unpack(), b.unpack()) {
351                (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
352                    ValuePairs::Regions(ExpectedFound::new(a, b))
353                }
354                (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
355                    ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
356                }
357                (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
358                    ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
359                }
360                _ => bug!("relating different kinds: {a:?} {b:?}"),
361            },
362        }
363    }
364}
365
366impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
367    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
368        TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) }
369    }
370}
371
372impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
373    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
374        TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
375    }
376}
377
378impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
379    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
380        TypeTrace {
381            cause: cause.clone(),
382            values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())),
383        }
384    }
385}
386
387impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
388    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
389        TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) }
390    }
391}
392
393impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
394    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
395        TypeTrace {
396            cause: cause.clone(),
397            values: ValuePairs::PolySigs(ExpectedFound::new(
398                ty::Binder::dummy(a),
399                ty::Binder::dummy(b),
400            )),
401        }
402    }
403}
404
405impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
406    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
407        TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) }
408    }
409}
410
411impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
412    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
413        TypeTrace {
414            cause: cause.clone(),
415            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)),
416        }
417    }
418}
419
420impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> {
421    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
422        TypeTrace {
423            cause: cause.clone(),
424            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(
425                ty::Binder::dummy(a),
426                ty::Binder::dummy(b),
427            )),
428        }
429    }
430}
431
432impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
433    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
434        TypeTrace {
435            cause: cause.clone(),
436            values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)),
437        }
438    }
439}
440
441impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> {
442    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
443        TypeTrace {
444            cause: cause.clone(),
445            values: ValuePairs::ExistentialProjection(ExpectedFound::new(
446                ty::Binder::dummy(a),
447                ty::Binder::dummy(b),
448            )),
449        }
450    }
451}