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