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            in_hir_typeck: self.in_hir_typeck,
75            skip_leak_check: self.skip_leak_check,
76            inner: self.inner.clone(),
77            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
78            selection_cache: self.selection_cache.clone(),
79            evaluation_cache: self.evaluation_cache.clone(),
80            reported_trait_errors: self.reported_trait_errors.clone(),
81            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
82            tainted_by_errors: self.tainted_by_errors.clone(),
83            universe: self.universe.clone(),
84            next_trait_solver: self.next_trait_solver,
85            obligation_inspector: self.obligation_inspector.clone(),
86        }
87    }
88
89    /// Forks the inference context, creating a new inference context with the same inference
90    /// variables in the same state, except possibly changing the intercrate mode. This can be
91    /// used to "branch off" many tests from the same common state. Used in negative coherence.
92    pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self {
93        // Unlike `fork`, this invalidates all cache entries as they may depend on the
94        // typing mode.
95        let forked = Self {
96            tcx: self.tcx,
97            typing_mode,
98            considering_regions: self.considering_regions,
99            in_hir_typeck: self.in_hir_typeck,
100            skip_leak_check: self.skip_leak_check,
101            inner: self.inner.clone(),
102            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
103            selection_cache: Default::default(),
104            evaluation_cache: Default::default(),
105            reported_trait_errors: self.reported_trait_errors.clone(),
106            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
107            tainted_by_errors: self.tainted_by_errors.clone(),
108            universe: self.universe.clone(),
109            next_trait_solver: self.next_trait_solver,
110            obligation_inspector: self.obligation_inspector.clone(),
111        };
112        forked.inner.borrow_mut().projection_cache().clear();
113        forked
114    }
115}
116
117pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
118    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>;
119}
120
121impl<'a, 'tcx> At<'a, 'tcx> {
122    /// Makes `actual <: expected`. For example, if type-checking a
123    /// call like `foo(x)`, where `foo: fn(i32)`, you might have
124    /// `sup(i32, x)`, since the "expected" type is the type that
125    /// appears in the signature.
126    pub fn sup<T>(
127        self,
128        define_opaque_types: DefineOpaqueTypes,
129        expected: T,
130        actual: T,
131    ) -> InferResult<'tcx, ()>
132    where
133        T: ToTrace<'tcx>,
134    {
135        if self.infcx.next_trait_solver {
136            NextSolverRelate::relate(
137                self.infcx,
138                self.param_env,
139                expected,
140                ty::Contravariant,
141                actual,
142                self.cause.span,
143            )
144            .map(|goals| self.goals_to_obligations(goals))
145        } else {
146            let mut op = TypeRelating::new(
147                self.infcx,
148                ToTrace::to_trace(self.cause, expected, actual),
149                self.param_env,
150                define_opaque_types,
151                ty::Contravariant,
152            );
153            op.relate(expected, actual)?;
154            Ok(InferOk { value: (), obligations: op.into_obligations() })
155        }
156    }
157
158    /// Makes `expected <: actual`.
159    pub fn sub<T>(
160        self,
161        define_opaque_types: DefineOpaqueTypes,
162        expected: T,
163        actual: T,
164    ) -> InferResult<'tcx, ()>
165    where
166        T: ToTrace<'tcx>,
167    {
168        if self.infcx.next_trait_solver {
169            NextSolverRelate::relate(
170                self.infcx,
171                self.param_env,
172                expected,
173                ty::Covariant,
174                actual,
175                self.cause.span,
176            )
177            .map(|goals| self.goals_to_obligations(goals))
178        } else {
179            let mut op = TypeRelating::new(
180                self.infcx,
181                ToTrace::to_trace(self.cause, expected, actual),
182                self.param_env,
183                define_opaque_types,
184                ty::Covariant,
185            );
186            op.relate(expected, actual)?;
187            Ok(InferOk { value: (), obligations: op.into_obligations() })
188        }
189    }
190
191    /// Makes `expected == actual`.
192    pub fn eq<T>(
193        self,
194        define_opaque_types: DefineOpaqueTypes,
195        expected: T,
196        actual: T,
197    ) -> InferResult<'tcx, ()>
198    where
199        T: ToTrace<'tcx>,
200    {
201        self.eq_trace(
202            define_opaque_types,
203            ToTrace::to_trace(self.cause, expected, actual),
204            expected,
205            actual,
206        )
207    }
208
209    /// Makes `expected == actual`.
210    pub fn eq_trace<T>(
211        self,
212        define_opaque_types: DefineOpaqueTypes,
213        trace: TypeTrace<'tcx>,
214        expected: T,
215        actual: T,
216    ) -> InferResult<'tcx, ()>
217    where
218        T: Relate<TyCtxt<'tcx>>,
219    {
220        if self.infcx.next_trait_solver {
221            NextSolverRelate::relate(
222                self.infcx,
223                self.param_env,
224                expected,
225                ty::Invariant,
226                actual,
227                self.cause.span,
228            )
229            .map(|goals| self.goals_to_obligations(goals))
230        } else {
231            let mut op = TypeRelating::new(
232                self.infcx,
233                trace,
234                self.param_env,
235                define_opaque_types,
236                ty::Invariant,
237            );
238            op.relate(expected, actual)?;
239            Ok(InferOk { value: (), obligations: op.into_obligations() })
240        }
241    }
242
243    pub fn relate<T>(
244        self,
245        define_opaque_types: DefineOpaqueTypes,
246        expected: T,
247        variance: ty::Variance,
248        actual: T,
249    ) -> InferResult<'tcx, ()>
250    where
251        T: ToTrace<'tcx>,
252    {
253        match variance {
254            ty::Covariant => self.sub(define_opaque_types, expected, actual),
255            ty::Invariant => self.eq(define_opaque_types, expected, actual),
256            ty::Contravariant => self.sup(define_opaque_types, expected, actual),
257
258            // We could make this make sense but it's not readily
259            // exposed and I don't feel like dealing with it. Note
260            // that bivariance in general does a bit more than just
261            // *nothing*, it checks that the types are the same
262            // "modulo variance" basically.
263            ty::Bivariant => panic!("Bivariant given to `relate()`"),
264        }
265    }
266
267    /// Computes the least-upper-bound, or mutual supertype, of two
268    /// values. The order of the arguments doesn't matter, but since
269    /// this can result in an error (e.g., if asked to compute LUB of
270    /// u32 and i32), it is meaningful to call one of them the
271    /// "expected type".
272    pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
273    where
274        T: ToTrace<'tcx>,
275    {
276        let mut op = LatticeOp::new(
277            self.infcx,
278            ToTrace::to_trace(self.cause, expected, actual),
279            self.param_env,
280            LatticeOpKind::Lub,
281        );
282        let value = op.relate(expected, actual)?;
283        Ok(InferOk { value, obligations: op.into_obligations() })
284    }
285
286    fn goals_to_obligations(
287        &self,
288        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
289    ) -> InferOk<'tcx, ()> {
290        InferOk {
291            value: (),
292            obligations: goals
293                .into_iter()
294                .map(|goal| {
295                    Obligation::new(
296                        self.infcx.tcx,
297                        self.cause.clone(),
298                        goal.param_env,
299                        goal.predicate,
300                    )
301                })
302                .collect(),
303        }
304    }
305}
306
307impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> {
308    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
309        match (a, b) {
310            (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => {
311                ToTrace::to_trace(cause, trait_ref_a, trait_ref_b)
312            }
313            (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => {
314                ToTrace::to_trace(cause, ty_a, ty_b)
315            }
316            (ImplSubject::Trait(_), ImplSubject::Inherent(_))
317            | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => {
318                bug!("can not trace TraitRef and Ty");
319            }
320        }
321    }
322}
323
324impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
325    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
326        TypeTrace {
327            cause: cause.clone(),
328            values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
329        }
330    }
331}
332
333impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
334    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
335        TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) }
336    }
337}
338
339impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
340    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
341        TypeTrace {
342            cause: cause.clone(),
343            values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
344        }
345    }
346}
347
348impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
349    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
350        TypeTrace {
351            cause: cause.clone(),
352            values: match (a.kind(), b.kind()) {
353                (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
354                    ValuePairs::Regions(ExpectedFound::new(a, b))
355                }
356                (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
357                    ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
358                }
359                (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
360                    ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
361                }
362                _ => bug!("relating different kinds: {a:?} {b:?}"),
363            },
364        }
365    }
366}
367
368impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
369    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
370        TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) }
371    }
372}
373
374impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
375    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
376        TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
377    }
378}
379
380impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
381    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
382        TypeTrace {
383            cause: cause.clone(),
384            values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())),
385        }
386    }
387}
388
389impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
390    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
391        TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) }
392    }
393}
394
395impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
396    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
397        TypeTrace {
398            cause: cause.clone(),
399            values: ValuePairs::PolySigs(ExpectedFound::new(
400                ty::Binder::dummy(a),
401                ty::Binder::dummy(b),
402            )),
403        }
404    }
405}
406
407impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
408    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
409        TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) }
410    }
411}
412
413impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
414    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
415        TypeTrace {
416            cause: cause.clone(),
417            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)),
418        }
419    }
420}
421
422impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> {
423    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
424        TypeTrace {
425            cause: cause.clone(),
426            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(
427                ty::Binder::dummy(a),
428                ty::Binder::dummy(b),
429            )),
430        }
431    }
432}
433
434impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
435    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
436        TypeTrace {
437            cause: cause.clone(),
438            values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)),
439        }
440    }
441}
442
443impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> {
444    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
445        TypeTrace {
446            cause: cause.clone(),
447            values: ValuePairs::ExistentialProjection(ExpectedFound::new(
448                ty::Binder::dummy(a),
449                ty::Binder::dummy(b),
450            )),
451        }
452    }
453}