Skip to main content

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::ty::relate::solver_relating::RelateExt as NextSolverRelate;
30use rustc_middle::ty::{Const, ParamEnv, TypingMode};
31use rustc_span::bug;
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(#[automatically_derived]
impl ::core::fmt::Debug for DefineOpaqueTypes {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                DefineOpaqueTypes::Yes => "Yes",
                DefineOpaqueTypes::No => "No",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for DefineOpaqueTypes { }
#[automatically_derived]
impl ::core::cmp::PartialEq for DefineOpaqueTypes {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for DefineOpaqueTypes { }Eq, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DefineOpaqueTypes { }
#[automatically_derived]
impl ::core::clone::Clone for DefineOpaqueTypes {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DefineOpaqueTypes { }Copy)]
44pub enum DefineOpaqueTypes {
45    Yes,
46    No,
47}
48
49#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl<'a, 'tcx> ::core::clone::TrivialClone for At<'a, 'tcx> { }
#[automatically_derived]
impl<'a, 'tcx> ::core::clone::Clone for At<'a, 'tcx> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<&'a InferCtxt<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<&'a ObligationCause<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<ty::ParamEnv<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'a, 'tcx> ::core::marker::Copy for At<'a, 'tcx> { }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_hir_errors: self.reported_hir_errors.clone(),
82            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
83            tainted_by_errors: self.tainted_by_errors.clone(),
84            universe: self.universe.clone(),
85            placeholder_assumptions_for_next_solver: self
86                .placeholder_assumptions_for_next_solver
87                .clone(),
88            next_trait_solver: self.next_trait_solver,
89            enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(),
90            obligation_inspector: self.obligation_inspector.clone(),
91            canonicalizer_state: Default::default(),
92        }
93    }
94
95    /// Forks the inference context, creating a new inference context with the same inference
96    /// variables in the same state, except possibly changing the intercrate mode. This can be
97    /// used to "branch off" many tests from the same common state. Used in negative coherence.
98    pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self {
99        // Unlike `fork`, this invalidates all cache entries as they may depend on the
100        // typing mode.
101        let forked = Self {
102            tcx: self.tcx,
103            typing_mode,
104            considering_regions: self.considering_regions,
105            in_hir_typeck: self.in_hir_typeck,
106            skip_leak_check: self.skip_leak_check,
107            inner: self.inner.clone(),
108            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
109            selection_cache: Default::default(),
110            evaluation_cache: Default::default(),
111            reported_trait_errors: self.reported_trait_errors.clone(),
112            reported_hir_errors: self.reported_hir_errors.clone(),
113            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
114            tainted_by_errors: self.tainted_by_errors.clone(),
115            universe: self.universe.clone(),
116            placeholder_assumptions_for_next_solver: self
117                .placeholder_assumptions_for_next_solver
118                .clone(),
119            next_trait_solver: self.next_trait_solver,
120            enable_next_solver_overflow_fcw: self.enable_next_solver_overflow_fcw.clone(),
121            obligation_inspector: self.obligation_inspector.clone(),
122            canonicalizer_state: Default::default(),
123        };
124        forked.inner.borrow_mut().projection_cache().clear();
125        forked
126    }
127
128    /// Makes `actual <: expected`. For example, if type-checking a
129    /// call like `foo(x)`, where `foo: fn(i32)`, you might have
130    /// `sup(i32, x)`, since the "expected" type is the type that
131    /// appears in the signature.
132    ///
133    /// If possible, prefer the wrapper methods on `ObligationCtxt`,
134    /// `FnCtxt`, or `TypeChecker`.
135    pub fn sup_raw<T>(
136        &self,
137        cause: &ObligationCause<'tcx>,
138        param_env: ParamEnv<'tcx>,
139        define_opaque_types: DefineOpaqueTypes,
140        expected: T,
141        actual: T,
142    ) -> InferResult<'tcx, ()>
143    where
144        T: ToTrace<'tcx>,
145    {
146        if self.next_trait_solver {
147            NextSolverRelate::relate(
148                self,
149                param_env,
150                expected,
151                ty::Contravariant,
152                actual,
153                cause.span,
154            )
155            .map(|goals| self.goals_to_obligations(cause, goals))
156        } else {
157            let mut op = TypeRelating::new(
158                &self,
159                ToTrace::to_trace(cause, expected, actual),
160                param_env,
161                define_opaque_types,
162                ty::Contravariant,
163            );
164            op.relate(expected, actual)?;
165            Ok(InferOk { value: (), obligations: op.into_obligations() })
166        }
167    }
168
169    /// Makes `expected <: actual`.
170    ///
171    /// If possible, prefer the wrapper methods on `ObligationCtxt`,
172    /// `FnCtxt`, or `TypeChecker`.
173    pub fn sub_raw<T>(
174        self,
175        cause: &ObligationCause<'tcx>,
176        param_env: ParamEnv<'tcx>,
177        define_opaque_types: DefineOpaqueTypes,
178        expected: T,
179        actual: T,
180    ) -> InferResult<'tcx, ()>
181    where
182        T: ToTrace<'tcx>,
183    {
184        self.at(cause, param_env).sub(define_opaque_types, expected, actual)
185    }
186
187    /// Makes `expected == actual`.
188    ///
189    /// If possible, prefer the wrapper methods on `ObligationCtxt`,
190    /// `FnCtxt`, or `TypeChecker`.
191    pub fn eq_raw<T>(
192        self,
193        cause: &ObligationCause<'tcx>,
194        param_env: ParamEnv<'tcx>,
195        define_opaque_types: DefineOpaqueTypes,
196        expected: T,
197        actual: T,
198    ) -> InferResult<'tcx, ()>
199    where
200        T: ToTrace<'tcx>,
201    {
202        self.eq_trace_raw(
203            cause,
204            param_env,
205            define_opaque_types,
206            ToTrace::to_trace(cause, expected, actual),
207            expected,
208            actual,
209        )
210    }
211
212    /// Makes `expected == actual`.
213    ///
214    /// If possible, prefer the wrapper methods on `ObligationCtxt`,
215    /// `FnCtxt`, or `TypeChecker`.
216    pub fn eq_trace_raw<T>(
217        self,
218        cause: &ObligationCause<'tcx>,
219        param_env: ParamEnv<'tcx>,
220        define_opaque_types: DefineOpaqueTypes,
221        trace: TypeTrace<'tcx>,
222        expected: T,
223        actual: T,
224    ) -> InferResult<'tcx, ()>
225    where
226        T: Relate<TyCtxt<'tcx>>,
227    {
228        self.at(cause, param_env).eq_trace(define_opaque_types, trace, expected, actual)
229    }
230
231    /// If possible, prefer the wrapper methods on `ObligationCtxt`,
232    /// `FnCtxt`, or `TypeChecker`.
233    pub fn relate_raw<T>(
234        self,
235        cause: &ObligationCause<'tcx>,
236        param_env: ParamEnv<'tcx>,
237        define_opaque_types: DefineOpaqueTypes,
238        expected: T,
239        variance: ty::Variance,
240        actual: T,
241    ) -> InferResult<'tcx, ()>
242    where
243        T: ToTrace<'tcx>,
244    {
245        self.at(cause, param_env).relate(define_opaque_types, expected, variance, actual)
246    }
247
248    /// Computes the least-upper-bound, or mutual supertype, of two
249    /// values. The order of the arguments doesn't matter, but since
250    /// this can result in an error (e.g., if asked to compute LUB of
251    /// u32 and i32), it is meaningful to call one of them the
252    /// "expected type".
253    ///
254    /// If possible, prefer the wrapper methods on `ObligationCtxt`,
255    /// `FnCtxt`, or `TypeChecker`.
256    pub fn lub_raw<T>(
257        self,
258        cause: &ObligationCause<'tcx>,
259        param_env: ParamEnv<'tcx>,
260        expected: T,
261        actual: T,
262    ) -> InferResult<'tcx, T>
263    where
264        T: ToTrace<'tcx>,
265    {
266        self.at(cause, param_env).lub(expected, actual)
267    }
268
269    pub fn goals_to_obligations(
270        &self,
271        cause: &ObligationCause<'tcx>,
272        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
273    ) -> InferOk<'tcx, ()> {
274        InferOk {
275            value: (),
276            obligations: goals
277                .into_iter()
278                .map(|goal| {
279                    Obligation::new(self.tcx, cause.clone(), goal.param_env, goal.predicate)
280                })
281                .collect(),
282        }
283    }
284}
285
286pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy {
287    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>;
288}
289
290impl<'a, 'tcx> At<'a, 'tcx> {
291    /// Makes `expected <: actual`.
292    ///
293    /// FIXME: To be removed in favor of the [`InferCtxt::sub_raw`] method instead.
294    pub fn sub<T>(
295        self,
296        define_opaque_types: DefineOpaqueTypes,
297        expected: T,
298        actual: T,
299    ) -> InferResult<'tcx, ()>
300    where
301        T: ToTrace<'tcx>,
302    {
303        if self.infcx.next_trait_solver {
304            NextSolverRelate::relate(
305                self.infcx,
306                self.param_env,
307                expected,
308                ty::Covariant,
309                actual,
310                self.cause.span,
311            )
312            .map(|goals| self.goals_to_obligations(goals))
313        } else {
314            let mut op = TypeRelating::new(
315                self.infcx,
316                ToTrace::to_trace(self.cause, expected, actual),
317                self.param_env,
318                define_opaque_types,
319                ty::Covariant,
320            );
321            op.relate(expected, actual)?;
322            Ok(InferOk { value: (), obligations: op.into_obligations() })
323        }
324    }
325
326    /// Makes `expected == actual`.
327    ///
328    /// FIXME: To be removed in favor of the [`InferCtxt::eq_raw`] method instead.
329    pub fn eq<T>(
330        self,
331        define_opaque_types: DefineOpaqueTypes,
332        expected: T,
333        actual: T,
334    ) -> InferResult<'tcx, ()>
335    where
336        T: ToTrace<'tcx>,
337    {
338        self.eq_trace(
339            define_opaque_types,
340            ToTrace::to_trace(self.cause, expected, actual),
341            expected,
342            actual,
343        )
344    }
345
346    /// Makes `expected == actual`.
347    ///
348    /// FIXME: To be removed in favor of the [`InferCtxt::eq_trace_raw`] method instead.
349    pub fn eq_trace<T>(
350        self,
351        define_opaque_types: DefineOpaqueTypes,
352        trace: TypeTrace<'tcx>,
353        expected: T,
354        actual: T,
355    ) -> InferResult<'tcx, ()>
356    where
357        T: Relate<TyCtxt<'tcx>>,
358    {
359        if self.infcx.next_trait_solver {
360            NextSolverRelate::relate(
361                self.infcx,
362                self.param_env,
363                expected,
364                ty::Invariant,
365                actual,
366                self.cause.span,
367            )
368            .map(|goals| self.goals_to_obligations(goals))
369        } else {
370            let mut op = TypeRelating::new(
371                self.infcx,
372                trace,
373                self.param_env,
374                define_opaque_types,
375                ty::Invariant,
376            );
377            op.relate(expected, actual)?;
378            Ok(InferOk { value: (), obligations: op.into_obligations() })
379        }
380    }
381
382    /// FIXME: To be removed in favor of the [`InferCtxt::relate_raw`] method instead.
383    pub fn relate<T>(
384        self,
385        define_opaque_types: DefineOpaqueTypes,
386        expected: T,
387        variance: ty::Variance,
388        actual: T,
389    ) -> InferResult<'tcx, ()>
390    where
391        T: ToTrace<'tcx>,
392    {
393        match variance {
394            ty::Covariant => self.sub(define_opaque_types, expected, actual),
395            ty::Invariant => self.eq(define_opaque_types, expected, actual),
396            ty::Contravariant => self.infcx.sup_raw(
397                self.cause,
398                self.param_env,
399                define_opaque_types,
400                expected,
401                actual,
402            ),
403
404            // We could make this make sense but it's not readily
405            // exposed and I don't feel like dealing with it. Note
406            // that bivariance in general does a bit more than just
407            // *nothing*, it checks that the types are the same
408            // "modulo variance" basically.
409            ty::Bivariant => {
    ::core::panicking::panic_fmt(format_args!("Bivariant given to `relate()`"));
}panic!("Bivariant given to `relate()`"),
410        }
411    }
412
413    /// Computes the least-upper-bound, or mutual supertype, of two
414    /// values. The order of the arguments doesn't matter, but since
415    /// this can result in an error (e.g., if asked to compute LUB of
416    /// u32 and i32), it is meaningful to call one of them the
417    /// "expected type".
418    ///
419    /// FIXME: To be removed in favor of the [`InferCtxt::lub_raw`] method instead.
420    pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T>
421    where
422        T: ToTrace<'tcx>,
423    {
424        let mut op = LatticeOp::new(
425            self.infcx,
426            ToTrace::to_trace(self.cause, expected, actual),
427            self.param_env,
428            LatticeOpKind::Lub,
429        );
430        let value = op.relate(expected, actual)?;
431        Ok(InferOk { value, obligations: op.into_obligations() })
432    }
433
434    /// FIXME: To be removed in favor of the [`InferCtxt::goals_to_obligations`] method instead.
435    fn goals_to_obligations(
436        &self,
437        goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
438    ) -> InferOk<'tcx, ()> {
439        InferOk {
440            value: (),
441            obligations: goals
442                .into_iter()
443                .map(|goal| {
444                    Obligation::new(
445                        self.infcx.tcx,
446                        self.cause.clone(),
447                        goal.param_env,
448                        goal.predicate,
449                    )
450                })
451                .collect(),
452        }
453    }
454}
455
456impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
457    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
458        TypeTrace {
459            cause: cause.clone(),
460            values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
461        }
462    }
463}
464
465impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
466    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
467        TypeTrace { cause: cause.clone(), values: ValuePairs::Regions(ExpectedFound::new(a, b)) }
468    }
469}
470
471impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
472    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
473        TypeTrace {
474            cause: cause.clone(),
475            values: ValuePairs::Terms(ExpectedFound::new(a.into(), b.into())),
476        }
477    }
478}
479
480impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> {
481    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
482        TypeTrace {
483            cause: cause.clone(),
484            values: match (a.kind(), b.kind()) {
485                (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
486                    ValuePairs::Regions(ExpectedFound::new(a, b))
487                }
488                (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
489                    ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
490                }
491                (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
492                    ValuePairs::Terms(ExpectedFound::new(a.into(), b.into()))
493                }
494                _ => ::rustc_span::macros::bug_impl(None,
    format_args!("relating different kinds: {0:?} {1:?}", a, b),
    Location::caller())bug!("relating different kinds: {a:?} {b:?}"),
495            },
496        }
497    }
498}
499
500impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
501    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
502        TypeTrace { cause: cause.clone(), values: ValuePairs::Terms(ExpectedFound::new(a, b)) }
503    }
504}
505
506impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
507    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
508        TypeTrace { cause: cause.clone(), values: ValuePairs::TraitRefs(ExpectedFound::new(a, b)) }
509    }
510}
511
512impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
513    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
514        TypeTrace {
515            cause: cause.clone(),
516            values: ValuePairs::Aliases(ExpectedFound::new(a.into(), b.into())),
517        }
518    }
519}
520
521impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
522    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
523        TypeTrace { cause: cause.clone(), values: ValuePairs::Aliases(ExpectedFound::new(a, b)) }
524    }
525}
526
527impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
528    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
529        TypeTrace {
530            cause: cause.clone(),
531            values: ValuePairs::PolySigs(ExpectedFound::new(
532                ty::Binder::dummy(a),
533                ty::Binder::dummy(b),
534            )),
535        }
536    }
537}
538
539impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> {
540    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
541        TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new(a, b)) }
542    }
543}
544
545impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> {
546    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
547        TypeTrace {
548            cause: cause.clone(),
549            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a, b)),
550        }
551    }
552}
553
554impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> {
555    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
556        TypeTrace {
557            cause: cause.clone(),
558            values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(
559                ty::Binder::dummy(a),
560                ty::Binder::dummy(b),
561            )),
562        }
563    }
564}
565
566impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> {
567    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
568        TypeTrace {
569            cause: cause.clone(),
570            values: ValuePairs::ExistentialProjection(ExpectedFound::new(a, b)),
571        }
572    }
573}
574
575impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> {
576    fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> {
577        TypeTrace {
578            cause: cause.clone(),
579            values: ValuePairs::ExistentialProjection(ExpectedFound::new(
580                ty::Binder::dummy(a),
581                ty::Binder::dummy(b),
582            )),
583        }
584    }
585}