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