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